[v2,2/6] gdb/ser-pipe.c: Duplicate the file descriptors

Message ID 20240119115659.491195-4-ahajkova@redhat.com
State New
Headers
Series Add vDefaultInferiorFd feature |

Checks

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

Commit Message

Alexandra Hájková Jan. 19, 2024, 11:56 a.m. UTC
  Duplicate the numbers of STDOUT/STDIN/STDERR file descriptors
GDB is connected to. Preserved numbers of the file descriptors
could be then sent to the gdbserver. If gdbserver is run locally
and will accept the numbers of the file descriptors, it can start
the inferior connected to the same STDIN/OUT/ERR, GDB is connected to.
---
 gdb/ser-pipe.c | 40 ++++++++++++++++++++++++++++++++++++++++
 gdb/serial.c   |  4 ++++
 gdb/serial.h   |  4 ++++
 3 files changed, 48 insertions(+)
  

Patch

diff --git a/gdb/ser-pipe.c b/gdb/ser-pipe.c
index 842b656eb5a..849926c179b 100644
--- a/gdb/ser-pipe.c
+++ b/gdb/ser-pipe.c
@@ -77,6 +77,32 @@  pipe_open (struct serial *scb, const char *name)
       perror_with_name (_("could not open socket pair"), save);
     }
 
+  /* Preserve STDIN/STDOUT/STDERR so they won't be closed on
+     exec later, after we fork.  */
+  int saved_stdin = dup (STDIN_FILENO);
+  int saved_stdout = dup (STDOUT_FILENO);
+  int saved_stderr = dup (STDERR_FILENO);
+  if (saved_stdin == -1 || saved_stdout == -1 || saved_stderr == -1)
+    {
+      /* If any FD failed to dup() then we can't used the default-fd mechanism,
+	 so close any files that succeeded.  */
+      if (saved_stdin == -1)
+	close (saved_stdin);
+      if (saved_stdout == -1)
+	close (saved_stdout);
+      if (saved_stderr == -1)
+	close (saved_stderr);
+      saved_stdin = saved_stdout = saved_stderr = -1;
+    }
+
+  mark_fd_no_cloexec (saved_stdout);
+  mark_fd_no_cloexec (saved_stdin);
+  mark_fd_no_cloexec (saved_stderr);
+
+  scb->fds[0] = saved_stdin;
+  scb->fds[1] = saved_stdout;
+  scb->fds[2] = saved_stderr;
+
   /* Create the child process to run the command in.  Note that the
      apparent call to vfork() below *might* actually be a call to
      fork() due to the fact that autoconf will ``#define vfork fork''
@@ -91,6 +117,12 @@  pipe_open (struct serial *scb, const char *name)
       close (pdes[1]);
       close (err_pdes[0]);
       close (err_pdes[1]);
+      close (saved_stdout);
+      close (saved_stdin);
+      close (saved_stderr);
+      scb->fds[0] = -1;
+      scb->fds[1] = -1;
+      scb->fds[2] = -1;
       perror_with_name (_("could not vfork"), save);
     }
 
@@ -140,6 +172,14 @@  pipe_open (struct serial *scb, const char *name)
   close (pdes[1]);
   if (err_pdes[1] != -1)
     close (err_pdes[1]);
+
+  unmark_fd_no_cloexec(saved_stdout);
+  unmark_fd_no_cloexec(saved_stdin);
+  unmark_fd_no_cloexec(saved_stderr);
+  close (saved_stdout);
+  close (saved_stdin);
+  close (saved_stderr);
+
   /* :end chunk */
   state = XNEW (struct pipe_state);
   state->pid = pid;
diff --git a/gdb/serial.c b/gdb/serial.c
index 734a580ed02..8fe7bcfe4b4 100644
--- a/gdb/serial.c
+++ b/gdb/serial.c
@@ -180,6 +180,10 @@  new_serial (const struct serial_ops *ops)
 
   scb->ops = ops;
 
+  scb->fds[0] = -1;
+  scb->fds[1] = -1;
+  scb->fds[2] = -1;
+
   scb->bufp = scb->buf;
   scb->error_fd = -1;
   scb->refcnt = 1;
diff --git a/gdb/serial.h b/gdb/serial.h
index 69507e69295..bfec99ad7c6 100644
--- a/gdb/serial.h
+++ b/gdb/serial.h
@@ -254,6 +254,10 @@  struct serial
     int async_state;		/* Async internal state.  */
     void *async_context;	/* Async event thread's context */
     serial_event_ftype *async_handler;/* Async event handler */
+
+    /* File descriptors for preserved STDIN/STDOUT/STDERR
+       to be sent to gdbserver when run locally.  */
+    int fds[3];
   };
 
 struct serial_ops