Fix crash when creating index from index
[binutils-gdb.git] / gdb / inflow.c
index 163e28cada17967a707602f9fccf84f5c3421d92..9c7e2907625a9004a1cf7b67ac429082a8ef97d1 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-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "observable.h"
 #include <signal.h>
 #include <fcntl.h>
-#include "gdb_select.h"
+#include "gdbsupport/gdb_select.h"
 
-#include "inflow.h"
 #include "gdbcmd.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>
@@ -58,13 +58,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 +85,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,35 +108,6 @@ 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
@@ -147,7 +123,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 +172,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.  */
@@ -327,8 +303,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)
@@ -406,7 +382,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,9 +492,9 @@ 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 */
        }
@@ -549,12 +525,12 @@ child_interrupt (struct target_ops *self)
   thread_info *resumed = NULL;
   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;
     }
 
@@ -623,16 +599,11 @@ child_pass_ctrlc (struct target_ops *self)
 }
 
 /* Per-inferior data key.  */
-static const struct inferior_data *inflow_inferior_data;
+static const struct 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
@@ -643,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;
 }
@@ -662,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
@@ -684,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);
@@ -705,18 +658,16 @@ copy_terminal_info (struct inferior *to, struct inferior *from)
 void
 swap_terminal_info (inferior *a, inferior *b)
 {
-  terminal_info *info_a
-    = (terminal_info *) inferior_data (a, inflow_inferior_data);
-  terminal_info *info_b
-    = (terminal_info *) inferior_data (a, inflow_inferior_data);
+  terminal_info *info_a = inflow_inferior_data.get (a);
+  terminal_info *info_b = inflow_inferior_data.get (b);
 
-  set_inferior_data (a, inflow_inferior_data, info_b);
-  set_inferior_data (b, inflow_inferior_data, info_a);
+  inflow_inferior_data.set (a, info_b);
+  inflow_inferior_data.set (b, info_a);
 
   std::swap (a->terminal_state, b->terminal_state);
 }
 
-void
+static void
 info_terminal_command (const char *arg, int from_tty)
 {
   target_terminal::info (arg, from_tty);
@@ -730,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;
     }
 
@@ -740,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.  */
   {
@@ -749,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)
@@ -758,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
 
@@ -780,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);
@@ -808,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)
@@ -841,7 +792,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;
@@ -851,7 +802,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;
 
@@ -861,8 +812,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)
@@ -897,7 +848,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)
@@ -905,15 +856,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
@@ -937,7 +884,7 @@ 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_set = 1;
@@ -970,7 +917,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 ();
@@ -996,8 +943,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."));
@@ -1005,8 +953,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");
 }