]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/inflow.c
aarch64: correct SVE2.1 ld2q (scalar plus scalar)
[thirdparty/binutils-gdb.git] / gdb / inflow.c
index caff646207098c9938b43ccb671a39343c5ae910..773ac0ba4997e20172e72761421775af901c54fd 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to ptrace, for GDB when running under Unix.
-   Copyright (C) 1986-2018 Free Software Foundation, Inc.
+   Copyright (C) 1986-2024 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -16,7 +16,6 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include "defs.h"
 #include "frame.h"
 #include "inferior.h"
 #include "command.h"
 #include "observable.h"
 #include <signal.h>
 #include <fcntl.h>
-#include "gdb_select.h"
+#include "gdbsupport/gdb_select.h"
 
-#include "inflow.h"
-#include "gdbcmd.h"
+#include "cli/cli-cmds.h"
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 #endif
-#include "job-control.h"
+#include "gdbsupport/job-control.h"
+#include "gdbsupport/scoped_ignore_sigttou.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
+
 #ifndef O_NOCTTY
 #define O_NOCTTY 0
 #endif
@@ -58,13 +61,18 @@ static struct serial *stdin_serial;
    the inferior is resumed in the foreground.  */
 struct terminal_info
 {
+  terminal_info () = default;
+  ~terminal_info ();
+
+  terminal_info &operator= (const terminal_info &) = default;
+
   /* The name of the tty (from the `tty' command) that we gave to the
      inferior when it was started.  */
-  char *run_terminal;
+  std::string run_terminal;
 
   /* TTY state.  We save it whenever the inferior stops, and restore
      it when it resumes in the foreground.  */
-  serial_ttystate ttystate;
+  serial_ttystate ttystate {};
 
 #ifdef HAVE_TERMIOS_H
   /* The terminal's foreground process group.  Saved whenever the
@@ -80,11 +88,11 @@ struct terminal_info
      inf2's pgrp in the foreground instead of inf1's (which would be
      problematic since it would be left stopped: Ctrl-C wouldn't work,
      for example).  */
-  pid_t process_group;
+  pid_t process_group = 0;
 #endif
 
   /* fcntl flags.  Saved and restored just like ttystate.  */
-  int tflags;
+  int tflags = 0;
 };
 
 /* Our own tty state, which we restore every time we need to deal with
@@ -103,43 +111,14 @@ static serial_ttystate initial_gdb_ttystate;
 
 static struct terminal_info *get_inflow_inferior_data (struct inferior *);
 
-/* RAII class used to ignore SIGTTOU in a scope.  */
-
-class scoped_ignore_sigttou
-{
-public:
-  scoped_ignore_sigttou ()
-  {
-#ifdef SIGTTOU
-    if (job_control)
-      m_osigttou = signal (SIGTTOU, SIG_IGN);
-#endif
-  }
-
-  ~scoped_ignore_sigttou ()
-  {
-#ifdef SIGTTOU
-    if (job_control)
-      signal (SIGTTOU, m_osigttou);
-#endif
-  }
-
-  DISABLE_COPY_AND_ASSIGN (scoped_ignore_sigttou);
-
-private:
-#ifdef SIGTTOU
-  sighandler_t m_osigttou = NULL;
-#endif
-};
-
 /* While the inferior is running, we want SIGINT and SIGQUIT to go to the
    inferior only.  If we have job control, that takes care of it.  If not,
    we save our handlers in these two variables and set SIGINT and SIGQUIT
    to SIG_IGN.  */
 
-static sighandler_t sigint_ours;
+static std::optional<sighandler_t> sigint_ours;
 #ifdef SIGQUIT
-static sighandler_t sigquit_ours;
+static std::optional<sighandler_t> sigquit_ours;
 #endif
 
 /* The name of the tty (from the `tty' command) that we're giving to
@@ -147,7 +126,7 @@ static sighandler_t sigquit_ours;
    be) used as a transient global by new_tty_prefork,
    create_tty_session, new_tty and new_tty_postfork, all called from
    fork_inferior, while forking a new child.  */
-static const char *inferior_thisrun_terminal;
+static std::string inferior_thisrun_terminal;
 
 /* Track who owns GDB's terminal (is it GDB or some inferior?).  While
    target_terminal::is_ours() etc. tracks the core's intention and is
@@ -196,8 +175,8 @@ gdb_has_a_terminal (void)
 
 #define        OOPSY(what)     \
   if (result == -1)    \
-    fprintf_unfiltered(gdb_stderr, "[%s failed in terminal_inferior: %s]\n", \
-           what, safe_strerror (errno))
+    gdb_printf(gdb_stderr, "[%s failed in terminal_inferior: %s]\n",   \
+              what, safe_strerror (errno))
 
 /* Initialize the terminal settings we record for the inferior,
    before we actually run the inferior.  */
@@ -236,10 +215,9 @@ gdb_save_tty_state (void)
     }
 }
 
-/* Try to determine whether TTY is GDB's input terminal.  Returns
-   TRIBOOL_UNKNOWN if we can't tell.  */
+/* See inferior.h.  */
 
-static tribool
+tribool
 is_gdb_terminal (const char *tty)
 {
   struct stat gdb_tty;
@@ -260,26 +238,6 @@ is_gdb_terminal (const char *tty)
          : TRIBOOL_FALSE);
 }
 
-/* Helper for sharing_input_terminal.  Try to determine whether
-   inferior INF is using the same TTY for input as GDB is.  Returns
-   TRIBOOL_UNKNOWN if we can't tell.  */
-
-static tribool
-sharing_input_terminal_1 (inferior *inf)
-{
-  /* Using host-dependent code here is fine, because the
-     child_terminal_foo functions are meant to be used by child/native
-     targets.  */
-#if defined (__linux__) || defined (__sun__)
-  char buf[100];
-
-  xsnprintf (buf, sizeof (buf), "/proc/%d/fd/0", inf->pid);
-  return is_gdb_terminal (buf);
-#else
-  return TRIBOOL_UNKNOWN;
-#endif
-}
-
 /* Return true if the inferior is using the same TTY for input as GDB
    is.  If this is true, then we save/restore terminal flags/state.
 
@@ -311,7 +269,7 @@ sharing_input_terminal (inferior *inf)
 {
   terminal_info *tinfo = get_inflow_inferior_data (inf);
 
-  tribool res = sharing_input_terminal_1 (inf);
+  tribool res = sharing_input_terminal (inf->pid);
 
   if (res == TRIBOOL_UNKNOWN)
     {
@@ -327,8 +285,8 @@ sharing_input_terminal (inferior *inf)
         output was redirected to our terminal), and with a false
         positive we just end up trying to save/restore terminal
         settings when we didn't need to or we actually can't.  */
-      if (tinfo->run_terminal != NULL)
-       res = is_gdb_terminal (tinfo->run_terminal);
+      if (!tinfo->run_terminal.empty ())
+       res = is_gdb_terminal (tinfo->run_terminal.c_str ());
 
       /* If we still can't determine, assume yes.  */
       if (res == TRIBOOL_UNKNOWN)
@@ -377,7 +335,7 @@ child_terminal_inferior (struct target_ops *self)
 
       if (!job_control)
        {
-         sigint_ours = signal (SIGINT, SIG_IGN);
+         sigint_ours = install_sigint_handler (SIG_IGN);
 #ifdef SIGQUIT
          sigquit_ours = signal (SIGQUIT, SIG_IGN);
 #endif
@@ -390,11 +348,25 @@ child_terminal_inferior (struct target_ops *self)
             then restore whatever was the foreground pgrp the last
             time the inferior was running.  See also comments
             describing terminal_state::process_group.  */
-#ifdef HAVE_GETPGID
-         result = tcsetpgrp (0, getpgid (inf->pid));
-#else
-         result = tcsetpgrp (0, tinfo->process_group);
-#endif
+         pid_t pgrp = tinfo->process_group;
+#ifdef __CYGWIN__
+         /* The Windows native target uses Win32 routines to run or
+            attach to processes (CreateProcess / DebugActiveProcess),
+            so a Cygwin inferior has a Windows PID, rather than a
+            Cygwin PID.  We want to pass the Cygwin PID to Cygwin
+            tcsetpgrp if we have a Cygwin inferior, so try to convert
+            first.  If we have a non-Cygwin inferior, we'll end up
+            passing down the WINPID to tcsetpgrp, stored in
+            terminal_state::process_group.  tcsetpgrp still succeeds
+            in that case, and it seems preferable to switch the
+            foreground pgrp away from GDB, for consistency.  */
+         pid_t cygpid = cygwin_internal (CW_WINPID_TO_CYGWIN_PID, inf->pid);
+         if (cygpid <= cygwin_internal (CW_MAX_CYGWIN_PID))
+           pgrp = getpgid (cygpid);
+#elif defined (HAVE_GETPGID)
+         pgrp = getpgid (inf->pid);
+#endif
+         result = tcsetpgrp (0, pgrp);
          if (result == -1)
            {
 #if 0
@@ -406,7 +378,7 @@ child_terminal_inferior (struct target_ops *self)
                 process running on another terminal and we couldn't
                 tell whether it was sharing GDB's terminal (and so
                 assumed yes).  */
-             fprintf_unfiltered
+             gdb_printf
                (gdb_stderr,
                 "[tcsetpgrp failed in child_terminal_inferior: %s]\n",
                 safe_strerror (errno));
@@ -516,18 +488,22 @@ child_terminal_ours_1 (target_terminal_state desired_state)
             used to check for an error here, so perhaps there are other
             such situations as well.  */
          if (result == -1)
-           fprintf_unfiltered (gdb_stderr,
-                               "[tcsetpgrp failed in child_terminal_ours: %s]\n",
-                               safe_strerror (errno));
+           gdb_printf (gdb_stderr,
+                       "[tcsetpgrp failed in child_terminal_ours: %s]\n",
+                       safe_strerror (errno));
 #endif
 #endif /* termios */
        }
 
       if (!job_control && desired_state == target_terminal_state::is_ours)
        {
-         signal (SIGINT, sigint_ours);
+         if (sigint_ours.has_value ())
+           install_sigint_handler (*sigint_ours);
+         sigint_ours.reset ();
 #ifdef SIGQUIT
-         signal (SIGQUIT, sigquit_ours);
+         if (sigquit_ours.has_value ())
+           signal (SIGQUIT, *sigquit_ours);
+         sigquit_ours.reset ();
 #endif
        }
 
@@ -546,16 +522,15 @@ void
 child_interrupt (struct target_ops *self)
 {
   /* Interrupt the first inferior that has a resumed thread.  */
-  thread_info *thr;
   thread_info *resumed = NULL;
-  ALL_NON_EXITED_THREADS (thr)
+  for (thread_info *thr : all_non_exited_threads ())
     {
-      if (thr->executing)
+      if (thr->executing ())
        {
          resumed = thr;
          break;
        }
-      if (thr->suspend.waitstatus_pending_p)
+      if (thr->has_pending_waitstatus ())
        resumed = thr;
     }
 
@@ -605,8 +580,7 @@ child_pass_ctrlc (struct target_ops *self)
 
   /* Otherwise, pass the Ctrl-C to the first inferior that was resumed
      in the foreground.  */
-  inferior *inf;
-  ALL_INFERIORS (inf)
+  for (inferior *inf : all_inferiors ())
     {
       if (inf->terminal_state != target_terminal_state::is_ours)
        {
@@ -625,16 +599,11 @@ child_pass_ctrlc (struct target_ops *self)
 }
 
 /* Per-inferior data key.  */
-static const struct inferior_data *inflow_inferior_data;
+static const registry<inferior>::key<terminal_info> inflow_inferior_data;
 
-static void
-inflow_inferior_data_cleanup (struct inferior *inf, void *arg)
+terminal_info::~terminal_info ()
 {
-  struct terminal_info *info = (struct terminal_info *) arg;
-
-  xfree (info->run_terminal);
-  xfree (info->ttystate);
-  xfree (info);
+  xfree (ttystate);
 }
 
 /* Get the current svr4 data.  If none is found yet, add it now.  This
@@ -645,12 +614,9 @@ get_inflow_inferior_data (struct inferior *inf)
 {
   struct terminal_info *info;
 
-  info = (struct terminal_info *) inferior_data (inf, inflow_inferior_data);
+  info = inflow_inferior_data.get (inf);
   if (info == NULL)
-    {
-      info = XCNEW (struct terminal_info);
-      set_inferior_data (inf, inflow_inferior_data, info);
-    }
+    info = inflow_inferior_data.emplace (inf);
 
   return info;
 }
@@ -664,18 +630,8 @@ get_inflow_inferior_data (struct inferior *inf)
 static void
 inflow_inferior_exit (struct inferior *inf)
 {
-  struct terminal_info *info;
-
   inf->terminal_state = target_terminal_state::is_ours;
-
-  info = (struct terminal_info *) inferior_data (inf, inflow_inferior_data);
-  if (info != NULL)
-    {
-      xfree (info->run_terminal);
-      xfree (info->ttystate);
-      xfree (info);
-      set_inferior_data (inf, inflow_inferior_data, NULL);
-    }
+  inflow_inferior_data.clear (inf);
 }
 
 void
@@ -686,15 +642,10 @@ copy_terminal_info (struct inferior *to, struct inferior *from)
   tinfo_to = get_inflow_inferior_data (to);
   tinfo_from = get_inflow_inferior_data (from);
 
-  xfree (tinfo_to->run_terminal);
   xfree (tinfo_to->ttystate);
 
   *tinfo_to = *tinfo_from;
 
-  if (tinfo_from->run_terminal)
-    tinfo_to->run_terminal
-      = xstrdup (tinfo_from->run_terminal);
-
   if (tinfo_from->ttystate)
     tinfo_to->ttystate
       = serial_copy_tty_state (stdin_serial, tinfo_from->ttystate);
@@ -702,7 +653,21 @@ copy_terminal_info (struct inferior *to, struct inferior *from)
   to->terminal_state = from->terminal_state;
 }
 
+/* See terminal.h.  */
+
 void
+swap_terminal_info (inferior *a, inferior *b)
+{
+  terminal_info *info_a = inflow_inferior_data.get (a);
+  terminal_info *info_b = inflow_inferior_data.get (b);
+
+  inflow_inferior_data.set (a, info_b);
+  inflow_inferior_data.set (b, info_a);
+
+  std::swap (a->terminal_state, b->terminal_state);
+}
+
+static void
 info_terminal_command (const char *arg, int from_tty)
 {
   target_terminal::info (arg, from_tty);
@@ -716,7 +681,7 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
 
   if (!gdb_has_a_terminal ())
     {
-      printf_filtered (_("This GDB does not control a terminal.\n"));
+      gdb_printf (_("This GDB does not control a terminal.\n"));
       return;
     }
 
@@ -726,8 +691,8 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
   inf = current_inferior ();
   tinfo = get_inflow_inferior_data (inf);
 
-  printf_filtered (_("Inferior's terminal status "
-                    "(currently saved by GDB):\n"));
+  gdb_printf (_("Inferior's terminal status "
+               "(currently saved by GDB):\n"));
 
   /* First the fcntl flags.  */
   {
@@ -735,7 +700,7 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
 
     flags = tinfo->tflags;
 
-    printf_filtered ("File descriptor flags = ");
+    gdb_printf ("File descriptor flags = ");
 
 #ifndef O_ACCMODE
 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
@@ -744,20 +709,20 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
     switch (flags & (O_ACCMODE))
       {
       case O_RDONLY:
-       printf_filtered ("O_RDONLY");
+       gdb_printf ("O_RDONLY");
        break;
       case O_WRONLY:
-       printf_filtered ("O_WRONLY");
+       gdb_printf ("O_WRONLY");
        break;
       case O_RDWR:
-       printf_filtered ("O_RDWR");
+       gdb_printf ("O_RDWR");
        break;
       }
     flags &= ~(O_ACCMODE);
 
 #ifdef O_NONBLOCK
     if (flags & O_NONBLOCK)
-      printf_filtered (" | O_NONBLOCK");
+      gdb_printf (" | O_NONBLOCK");
     flags &= ~O_NONBLOCK;
 #endif
 
@@ -766,27 +731,27 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
        print it as O_NONBLOCK, which is good cause that is what POSIX
        has, and the flag will already be cleared by the time we get here.  */
     if (flags & O_NDELAY)
-      printf_filtered (" | O_NDELAY");
+      gdb_printf (" | O_NDELAY");
     flags &= ~O_NDELAY;
 #endif
 
     if (flags & O_APPEND)
-      printf_filtered (" | O_APPEND");
+      gdb_printf (" | O_APPEND");
     flags &= ~O_APPEND;
 
 #if defined (O_BINARY)
     if (flags & O_BINARY)
-      printf_filtered (" | O_BINARY");
+      gdb_printf (" | O_BINARY");
     flags &= ~O_BINARY;
 #endif
 
     if (flags)
-      printf_filtered (" | 0x%x", flags);
-    printf_filtered ("\n");
+      gdb_printf (" | 0x%x", flags);
+    gdb_printf ("\n");
   }
 
 #ifdef HAVE_TERMIOS_H
-  printf_filtered ("Process group = %d\n", (int) tinfo->process_group);
+  gdb_printf ("Process group = %d\n", (int) tinfo->process_group);
 #endif
 
   serial_print_tty_state (stdin_serial, tinfo->ttystate, gdb_stdout);
@@ -794,19 +759,19 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
 \f
 /* NEW_TTY_PREFORK is called before forking a new child process,
    so we can record the state of ttys in the child to be formed.
-   TTYNAME is null if we are to share the terminal with gdb;
-   or points to a string containing the name of the desired tty.
+   TTYNAME is empty if we are to share the terminal with gdb;
+   otherwise it contains the name of the desired tty.
 
    NEW_TTY is called in new child processes under Unix, which will
    become debugger target processes.  This actually switches to
    the terminal specified in the NEW_TTY_PREFORK call.  */
 
 void
-new_tty_prefork (const char *ttyname)
+new_tty_prefork (std::string ttyname)
 {
   /* Save the name for later, for determining whether we and the child
      are sharing a tty.  */
-  inferior_thisrun_terminal = ttyname;
+  inferior_thisrun_terminal = std::move (ttyname);
 }
 
 #if !defined(__GO32__) && !defined(_WIN32)
@@ -818,7 +783,8 @@ check_syscall (const char *msg, int result)
 {
   if (result < 0)
     {
-      print_sys_errmsg (msg, errno);
+      gdb_printf (gdb_stderr, "%s:%s.\n", msg,
+                 safe_strerror (errno));
       _exit (1);
     }
 }
@@ -827,7 +793,7 @@ check_syscall (const char *msg, int result)
 void
 new_tty (void)
 {
-  if (inferior_thisrun_terminal == 0)
+  if (inferior_thisrun_terminal.empty ())
     return;
 #if !defined(__GO32__) && !defined(_WIN32)
   int tty;
@@ -837,7 +803,7 @@ new_tty (void)
      systems (SVR4 for example), this may cause a SIGTTOU, so temporarily
      ignore SIGTTOU.  */
   tty = open ("/dev/tty", O_RDWR);
-  if (tty > 0)
+  if (tty >= 0)
     {
       scoped_ignore_sigttou ignore_sigttou;
 
@@ -847,8 +813,8 @@ new_tty (void)
 #endif
 
   /* Now open the specified new terminal.  */
-  tty = open (inferior_thisrun_terminal, O_RDWR | O_NOCTTY);
-  check_syscall (inferior_thisrun_terminal, tty);
+  tty = open (inferior_thisrun_terminal.c_str (), O_RDWR | O_NOCTTY);
+  check_syscall (inferior_thisrun_terminal.c_str (), tty);
 
   /* Avoid use of dup2; doesn't exist on all systems.  */
   if (tty != 0)
@@ -883,7 +849,7 @@ new_tty (void)
 
 /* NEW_TTY_POSTFORK is called after forking a new child process, and
    adding it to the inferior table, to store the TTYNAME being used by
-   the child, or null if it sharing the terminal with gdb.  */
+   the child, or empty if it sharing the terminal with gdb.  */
 
 void
 new_tty_postfork (void)
@@ -891,15 +857,11 @@ new_tty_postfork (void)
   /* Save the name for later, for determining whether we and the child
      are sharing a tty.  */
 
-  if (inferior_thisrun_terminal)
-    {
-      struct inferior *inf = current_inferior ();
-      struct terminal_info *tinfo = get_inflow_inferior_data (inf);
-
-      tinfo->run_terminal = xstrdup (inferior_thisrun_terminal);
-    }
+  struct inferior *inf = current_inferior ();
+  struct terminal_info *tinfo = get_inflow_inferior_data (inf);
 
-  inferior_thisrun_terminal = NULL;
+  tinfo->run_terminal = std::move (inferior_thisrun_terminal);
+  inferior_thisrun_terminal.clear ();
 }
 
 \f
@@ -923,9 +885,9 @@ set_sigint_trap (void)
   struct inferior *inf = current_inferior ();
   struct terminal_info *tinfo = get_inflow_inferior_data (inf);
 
-  if (inf->attach_flag || tinfo->run_terminal)
+  if (inf->attach_flag || !tinfo->run_terminal.empty ())
     {
-      osig = signal (SIGINT, pass_signal);
+      osig = install_sigint_handler (pass_signal);
       osig_set = 1;
     }
   else
@@ -937,7 +899,7 @@ clear_sigint_trap (void)
 {
   if (osig_set)
     {
-      signal (SIGINT, osig);
+      install_sigint_handler (osig);
       osig_set = 0;
     }
 }
@@ -956,7 +918,7 @@ create_tty_session (void)
 #ifdef HAVE_SETSID
   pid_t ret;
 
-  if (!job_control || inferior_thisrun_terminal == 0)
+  if (!job_control || inferior_thisrun_terminal.empty ())
     return 0;
 
   ret = setsid ();
@@ -982,8 +944,9 @@ initialize_stdin_serial (void)
   stdin_serial = serial_fdopen (0);
 }
 
+void _initialize_inflow ();
 void
-_initialize_inflow (void)
+_initialize_inflow ()
 {
   add_info ("terminal", info_terminal_command,
            _("Print inferior's saved terminal status."));
@@ -991,8 +954,5 @@ _initialize_inflow (void)
   /* OK, figure out whether we have job control.  */
   have_job_control ();
 
-  gdb::observers::inferior_exit.attach (inflow_inferior_exit);
-
-  inflow_inferior_data
-    = register_inferior_data_with_cleanup (NULL, inflow_inferior_data_cleanup);
+  gdb::observers::inferior_exit.attach (inflow_inferior_exit, "inflow");
 }