| /* Low level interface to ptrace, for GDB when running under Unix. | 
 |    Copyright (C) 1986-2024 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    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 "frame.h" | 
 | #include "inferior.h" | 
 | #include "command.h" | 
 | #include "serial.h" | 
 | #include "terminal.h" | 
 | #include "target.h" | 
 | #include "gdbthread.h" | 
 | #include "observable.h" | 
 | #include <signal.h> | 
 | #include <fcntl.h> | 
 | #include "gdbsupport/gdb_select.h" | 
 |  | 
 | #include "cli/cli-cmds.h" | 
 | #ifdef HAVE_TERMIOS_H | 
 | #include <termios.h> | 
 | #endif | 
 | #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 | 
 |  | 
 | static void pass_signal (int); | 
 |  | 
 | static void child_terminal_ours_1 (target_terminal_state); | 
 |  | 
 | /* Record terminal status separately for debugger and inferior.  */ | 
 |  | 
 | static struct serial *stdin_serial; | 
 |  | 
 | /* Terminal related info we need to keep track of.  Each inferior | 
 |    holds an instance of this structure --- we save it whenever the | 
 |    corresponding inferior stops, and restore it to the terminal when | 
 |    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.  */ | 
 |   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 {}; | 
 |  | 
 | #ifdef HAVE_TERMIOS_H | 
 |   /* The terminal's foreground process group.  Saved whenever the | 
 |      inferior stops.  This is the pgrp displayed by "info terminal". | 
 |      Note that this may be not the inferior's actual process group, | 
 |      since each inferior that we spawn has its own process group, and | 
 |      only one can be in the foreground at a time.  When the inferior | 
 |      resumes, if we can determine the inferior's actual pgrp, then we | 
 |      make that the foreground pgrp instead of what was saved here. | 
 |      While it's a bit arbitrary which inferior's pgrp ends up in the | 
 |      foreground when we resume several inferiors, this at least makes | 
 |      'resume inf1+inf2' + 'stop all' + 'resume inf2' end up with | 
 |      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 = 0; | 
 | #endif | 
 |  | 
 |   /* fcntl flags.  Saved and restored just like ttystate.  */ | 
 |   int tflags = 0; | 
 | }; | 
 |  | 
 | /* Our own tty state, which we restore every time we need to deal with | 
 |    the terminal.  This is set once, when GDB first starts, and then | 
 |    whenever we enter/leave TUI mode (gdb_save_tty_state).  The | 
 |    settings of flags which readline saves and restores are | 
 |    unimportant.  */ | 
 | static struct terminal_info our_terminal_info; | 
 |  | 
 | /* Snapshot of the initial tty state taken during initialization of | 
 |    GDB, before readline/ncurses have had a chance to change it.  This | 
 |    is used as the initial tty state given to each new spawned | 
 |    inferior.  Unlike our_terminal_info, this is only ever set | 
 |    once.  */ | 
 | static serial_ttystate initial_gdb_ttystate; | 
 |  | 
 | static struct terminal_info *get_inflow_inferior_data (struct inferior *); | 
 |  | 
 | /* 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 std::optional<sighandler_t> sigint_ours; | 
 | #ifdef SIGQUIT | 
 | static std::optional<sighandler_t> sigquit_ours; | 
 | #endif | 
 |  | 
 | /* The name of the tty (from the `tty' command) that we're giving to | 
 |    the inferior when starting it up.  This is only (and should only | 
 |    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 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 | 
 |    independent of the target backend, this tracks the actual state of | 
 |    GDB's own tty.  So for example, | 
 |  | 
 |      (target_terminal::is_inferior () && gdb_tty_state == terminal_is_ours) | 
 |  | 
 |    is true when the (native) inferior is not sharing a terminal with | 
 |    GDB (e.g., because we attached to an inferior that is running on a | 
 |    different terminal).  */ | 
 | static target_terminal_state gdb_tty_state = target_terminal_state::is_ours; | 
 |  | 
 | /* See terminal.h.  */ | 
 |  | 
 | void | 
 | set_initial_gdb_ttystate (void) | 
 | { | 
 |   /* Note we can't do any of this in _initialize_inflow because at | 
 |      that point stdin_serial has not been created yet.  */ | 
 |  | 
 |   initial_gdb_ttystate = serial_get_tty_state (stdin_serial); | 
 |  | 
 |   if (initial_gdb_ttystate != NULL) | 
 |     { | 
 |       our_terminal_info.ttystate | 
 | 	= serial_copy_tty_state (stdin_serial, initial_gdb_ttystate); | 
 | #ifdef F_GETFL | 
 |       our_terminal_info.tflags = fcntl (0, F_GETFL, 0); | 
 | #endif | 
 | #ifdef HAVE_TERMIOS_H | 
 |       our_terminal_info.process_group = tcgetpgrp (0); | 
 | #endif | 
 |     } | 
 | } | 
 |  | 
 | /* Does GDB have a terminal (on stdin)?  */ | 
 |  | 
 | static int | 
 | gdb_has_a_terminal (void) | 
 | { | 
 |   return initial_gdb_ttystate != NULL; | 
 | } | 
 |  | 
 | /* Macro for printing errors from ioctl operations */ | 
 |  | 
 | #define	OOPSY(what)	\ | 
 |   if (result == -1)	\ | 
 |     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.  */ | 
 |  | 
 | void | 
 | child_terminal_init (struct target_ops *self) | 
 | { | 
 |   if (!gdb_has_a_terminal ()) | 
 |     return; | 
 |  | 
 |   inferior *inf = current_inferior (); | 
 |   terminal_info *tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 | #ifdef HAVE_TERMIOS_H | 
 |   /* A child we spawn should be a process group leader (PGID==PID) at | 
 |      this point, though that may not be true if we're attaching to an | 
 |      existing process.  */ | 
 |   tinfo->process_group = inf->pid; | 
 | #endif | 
 |  | 
 |   xfree (tinfo->ttystate); | 
 |   tinfo->ttystate = serial_copy_tty_state (stdin_serial, initial_gdb_ttystate); | 
 | } | 
 |  | 
 | /* Save the terminal settings again.  This is necessary for the TUI | 
 |    when it switches to TUI or non-TUI mode;  curses changes the terminal | 
 |    and gdb must be able to restore it correctly.  */ | 
 |  | 
 | void | 
 | gdb_save_tty_state (void) | 
 | { | 
 |   if (gdb_has_a_terminal ()) | 
 |     { | 
 |       xfree (our_terminal_info.ttystate); | 
 |       our_terminal_info.ttystate = serial_get_tty_state (stdin_serial); | 
 |     } | 
 | } | 
 |  | 
 | /* See inferior.h.  */ | 
 |  | 
 | tribool | 
 | is_gdb_terminal (const char *tty) | 
 | { | 
 |   struct stat gdb_tty; | 
 |   struct stat other_tty; | 
 |   int res; | 
 |  | 
 |   res = stat (tty, &other_tty); | 
 |   if (res == -1) | 
 |     return TRIBOOL_UNKNOWN; | 
 |  | 
 |   res = fstat (STDIN_FILENO, &gdb_tty); | 
 |   if (res == -1) | 
 |     return TRIBOOL_UNKNOWN; | 
 |  | 
 |   return ((gdb_tty.st_dev == other_tty.st_dev | 
 | 	   && gdb_tty.st_ino == other_tty.st_ino) | 
 | 	  ? TRIBOOL_TRUE | 
 | 	  : TRIBOOL_FALSE); | 
 | } | 
 |  | 
 | /* 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. | 
 |  | 
 |    This is necessary because if inf->attach_flag is set, we don't | 
 |    offhand know whether we are sharing a terminal with the inferior or | 
 |    not.  Attaching a process without a terminal is one case where we | 
 |    do not; attaching a process which we ran from the same shell as GDB | 
 |    via `&' is one case where we do. | 
 |  | 
 |    If we can't determine, we assume the TTY is being shared.  This | 
 |    works OK if you're only debugging one inferior.  However, if you're | 
 |    debugging more than one inferior, and e.g., one is spawned by GDB | 
 |    with "run" (sharing terminal with GDB), and another is attached to | 
 |    (and running on a different terminal, as is most common), then it | 
 |    matters, because we can only restore the terminal settings of one | 
 |    of the inferiors, and in that scenario, we want to restore the | 
 |    settings of the "run"'ed inferior. | 
 |  | 
 |    Note, this is not the same as determining whether GDB and the | 
 |    inferior are in the same session / connected to the same | 
 |    controlling tty.  An inferior (fork child) may call setsid, | 
 |    disconnecting itself from the ctty, while still leaving | 
 |    stdin/stdout/stderr associated with the original terminal.  If | 
 |    we're debugging that process, we should also save/restore terminal | 
 |    settings.  */ | 
 |  | 
 | static bool | 
 | sharing_input_terminal (inferior *inf) | 
 | { | 
 |   terminal_info *tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 |   tribool res = sharing_input_terminal (inf->pid); | 
 |  | 
 |   if (res == TRIBOOL_UNKNOWN) | 
 |     { | 
 |       /* As fallback, if we can't determine by stat'ing the inferior's | 
 | 	 tty directly (because it's not supported on this host) and | 
 | 	 the child was spawned, check whether run_terminal is our tty. | 
 | 	 This isn't ideal, since this is checking the child's | 
 | 	 controlling terminal, not the input terminal (which may have | 
 | 	 been redirected), but is still better than nothing.  A false | 
 | 	 positive ("set inferior-tty" points to our terminal, but I/O | 
 | 	 was redirected) is much more likely than a false negative | 
 | 	 ("set inferior-tty" points to some other terminal, and then | 
 | 	 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.empty ()) | 
 | 	res = is_gdb_terminal (tinfo->run_terminal.c_str ()); | 
 |  | 
 |       /* If we still can't determine, assume yes.  */ | 
 |       if (res == TRIBOOL_UNKNOWN) | 
 | 	return true; | 
 |     } | 
 |  | 
 |   return res == TRIBOOL_TRUE; | 
 | } | 
 |  | 
 | /* Put the inferior's terminal settings into effect.  This is | 
 |    preparation for starting or resuming the inferior.  */ | 
 |  | 
 | void | 
 | child_terminal_inferior (struct target_ops *self) | 
 | { | 
 |   /* If we resume more than one inferior in the foreground on GDB's | 
 |      terminal, then the first inferior's terminal settings "win". | 
 |      Note that every child process is put in its own process group, so | 
 |      the first process that ends up resumed ends up determining which | 
 |      process group the kernel forwards Ctrl-C/Ctrl-Z (SIGINT/SIGTTOU) | 
 |      to.  */ | 
 |   if (gdb_tty_state == target_terminal_state::is_inferior) | 
 |     return; | 
 |  | 
 |   inferior *inf = current_inferior (); | 
 |   terminal_info *tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 |   if (gdb_has_a_terminal () | 
 |       && tinfo->ttystate != NULL | 
 |       && sharing_input_terminal (inf)) | 
 |     { | 
 |       int result; | 
 |  | 
 |       /* Ignore SIGTTOU since it will happen when we try to set the | 
 | 	 terminal's state (if gdb_tty_state is currently | 
 | 	 ours_for_output).  */ | 
 |       scoped_ignore_sigttou ignore_sigttou; | 
 |  | 
 | #ifdef F_GETFL | 
 |       result = fcntl (0, F_SETFL, tinfo->tflags); | 
 |       OOPSY ("fcntl F_SETFL"); | 
 | #endif | 
 |  | 
 |       result = serial_set_tty_state (stdin_serial, tinfo->ttystate); | 
 |       OOPSY ("setting tty state"); | 
 |  | 
 |       if (!job_control) | 
 | 	{ | 
 | 	  sigint_ours = install_sigint_handler (SIG_IGN); | 
 | #ifdef SIGQUIT | 
 | 	  sigquit_ours = signal (SIGQUIT, SIG_IGN); | 
 | #endif | 
 | 	} | 
 |  | 
 |       if (job_control) | 
 | 	{ | 
 | #ifdef HAVE_TERMIOS_H | 
 | 	  /* If we can't tell the inferior's actual process group, | 
 | 	     then restore whatever was the foreground pgrp the last | 
 | 	     time the inferior was running.  See also comments | 
 | 	     describing terminal_state::process_group.  */ | 
 | 	  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 | 
 | 	      /* This fails if either GDB has no controlling terminal, | 
 | 		 e.g., running under 'setsid(1)', or if the inferior | 
 | 		 is not attached to GDB's controlling terminal.  E.g., | 
 | 		 if it called setsid to create a new session or used | 
 | 		 the TIOCNOTTY ioctl, or simply if we've attached to a | 
 | 		 process running on another terminal and we couldn't | 
 | 		 tell whether it was sharing GDB's terminal (and so | 
 | 		 assumed yes).  */ | 
 | 	      gdb_printf | 
 | 		(gdb_stderr, | 
 | 		 "[tcsetpgrp failed in child_terminal_inferior: %s]\n", | 
 | 		 safe_strerror (errno)); | 
 | #endif | 
 | 	    } | 
 | #endif | 
 | 	} | 
 |  | 
 |       gdb_tty_state = target_terminal_state::is_inferior; | 
 |     } | 
 | } | 
 |  | 
 | /* Put some of our terminal settings into effect, | 
 |    enough to get proper results from our output, | 
 |    but do not change into or out of RAW mode | 
 |    so that no input is discarded. | 
 |  | 
 |    After doing this, either terminal_ours or terminal_inferior | 
 |    should be called to get back to a normal state of affairs. | 
 |  | 
 |    N.B. The implementation is (currently) no different than | 
 |    child_terminal_ours.  See child_terminal_ours_1.  */ | 
 |  | 
 | void | 
 | child_terminal_ours_for_output (struct target_ops *self) | 
 | { | 
 |   child_terminal_ours_1 (target_terminal_state::is_ours_for_output); | 
 | } | 
 |  | 
 | /* Put our terminal settings into effect. | 
 |    First record the inferior's terminal settings | 
 |    so they can be restored properly later. | 
 |  | 
 |    N.B. Targets that want to use this with async support must build that | 
 |    support on top of this (e.g., the caller still needs to add stdin to the | 
 |    event loop).  E.g., see linux_nat_terminal_ours.  */ | 
 |  | 
 | void | 
 | child_terminal_ours (struct target_ops *self) | 
 | { | 
 |   child_terminal_ours_1 (target_terminal_state::is_ours); | 
 | } | 
 |  | 
 | /* Save the current terminal settings in the inferior's terminal_info | 
 |    cache.  */ | 
 |  | 
 | void | 
 | child_terminal_save_inferior (struct target_ops *self) | 
 | { | 
 |   /* Avoid attempting all the ioctl's when running in batch.  */ | 
 |   if (!gdb_has_a_terminal ()) | 
 |     return; | 
 |  | 
 |   inferior *inf = current_inferior (); | 
 |   terminal_info *tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 |   /* No need to save/restore if the inferior is not sharing GDB's | 
 |      tty.  */ | 
 |   if (!sharing_input_terminal (inf)) | 
 |     return; | 
 |  | 
 |   xfree (tinfo->ttystate); | 
 |   tinfo->ttystate = serial_get_tty_state (stdin_serial); | 
 |  | 
 | #ifdef HAVE_TERMIOS_H | 
 |   tinfo->process_group = tcgetpgrp (0); | 
 | #endif | 
 |  | 
 | #ifdef F_GETFL | 
 |   tinfo->tflags = fcntl (0, F_GETFL, 0); | 
 | #endif | 
 | } | 
 |  | 
 | /* Switch terminal state to DESIRED_STATE, either is_ours, or | 
 |    is_ours_for_output.  */ | 
 |  | 
 | static void | 
 | child_terminal_ours_1 (target_terminal_state desired_state) | 
 | { | 
 |   gdb_assert (desired_state != target_terminal_state::is_inferior); | 
 |  | 
 |   /* Avoid attempting all the ioctl's when running in batch.  */ | 
 |   if (!gdb_has_a_terminal ()) | 
 |     return; | 
 |  | 
 |   if (gdb_tty_state != desired_state) | 
 |     { | 
 |       int result ATTRIBUTE_UNUSED; | 
 |  | 
 |       /* Ignore SIGTTOU since it will happen when we try to set the | 
 | 	 terminal's pgrp.  */ | 
 |       scoped_ignore_sigttou ignore_sigttou; | 
 |  | 
 |       /* Set tty state to our_ttystate.  */ | 
 |       serial_set_tty_state (stdin_serial, our_terminal_info.ttystate); | 
 |  | 
 |       /* If we only want output, then leave the inferior's pgrp in the | 
 | 	 foreground, so that Ctrl-C/Ctrl-Z reach the inferior | 
 | 	 directly.  */ | 
 |       if (job_control && desired_state == target_terminal_state::is_ours) | 
 | 	{ | 
 | #ifdef HAVE_TERMIOS_H | 
 | 	  result = tcsetpgrp (0, our_terminal_info.process_group); | 
 | #if 0 | 
 | 	  /* This fails on Ultrix with EINVAL if you run the testsuite | 
 | 	     in the background with nohup, and then log out.  GDB never | 
 | 	     used to check for an error here, so perhaps there are other | 
 | 	     such situations as well.  */ | 
 | 	  if (result == -1) | 
 | 	    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) | 
 | 	{ | 
 | 	  if (sigint_ours.has_value ()) | 
 | 	    install_sigint_handler (*sigint_ours); | 
 | 	  sigint_ours.reset (); | 
 | #ifdef SIGQUIT | 
 | 	  if (sigquit_ours.has_value ()) | 
 | 	    signal (SIGQUIT, *sigquit_ours); | 
 | 	  sigquit_ours.reset (); | 
 | #endif | 
 | 	} | 
 |  | 
 | #ifdef F_GETFL | 
 |       result = fcntl (0, F_SETFL, our_terminal_info.tflags); | 
 | #endif | 
 |  | 
 |       gdb_tty_state = desired_state; | 
 |     } | 
 | } | 
 |  | 
 | /* Interrupt the inferior.  Implementation of target_interrupt for | 
 |    child/native targets.  */ | 
 |  | 
 | void | 
 | child_interrupt (struct target_ops *self) | 
 | { | 
 |   /* Interrupt the first inferior that has a resumed thread.  */ | 
 |   thread_info *resumed = NULL; | 
 |   for (thread_info *thr : all_non_exited_threads ()) | 
 |     { | 
 |       if (thr->executing ()) | 
 | 	{ | 
 | 	  resumed = thr; | 
 | 	  break; | 
 | 	} | 
 |       if (thr->has_pending_waitstatus ()) | 
 | 	resumed = thr; | 
 |     } | 
 |  | 
 |   if (resumed != NULL) | 
 |     { | 
 |       /* Note that unlike pressing Ctrl-C on the controlling terminal, | 
 | 	 here we only interrupt one process, not the whole process | 
 | 	 group.  This is because interrupting a process group (with | 
 | 	 either Ctrl-C or with kill(3) with negative PID) sends a | 
 | 	 SIGINT to each process in the process group, and we may not | 
 | 	 be debugging all processes in the process group.  */ | 
 | #ifndef _WIN32 | 
 |       kill (resumed->inf->pid, SIGINT); | 
 | #endif | 
 |     } | 
 | } | 
 |  | 
 | /* Pass a Ctrl-C to the inferior as-if a Ctrl-C was pressed while the | 
 |    inferior was in the foreground.  Implementation of | 
 |    target_pass_ctrlc for child/native targets.  */ | 
 |  | 
 | void | 
 | child_pass_ctrlc (struct target_ops *self) | 
 | { | 
 |   gdb_assert (!target_terminal::is_ours ()); | 
 |  | 
 | #ifdef HAVE_TERMIOS_H | 
 |   if (job_control) | 
 |     { | 
 |       pid_t term_pgrp = tcgetpgrp (0); | 
 |  | 
 |       /* If there's any inferior sharing our terminal, pass the SIGINT | 
 | 	 to the terminal's foreground process group.  This acts just | 
 | 	 like the user typed a ^C on the terminal while the inferior | 
 | 	 was in the foreground.  Note that using a negative process | 
 | 	 number in kill() is a System V-ism.  The proper BSD interface | 
 | 	 is killpg().  However, all modern BSDs support the System V | 
 | 	 interface too.  */ | 
 |  | 
 |       if (term_pgrp != -1 && term_pgrp != our_terminal_info.process_group) | 
 | 	{ | 
 | 	  kill (-term_pgrp, SIGINT); | 
 | 	  return; | 
 | 	} | 
 |     } | 
 | #endif | 
 |  | 
 |   /* Otherwise, pass the Ctrl-C to the first inferior that was resumed | 
 |      in the foreground.  */ | 
 |   for (inferior *inf : all_inferiors ()) | 
 |     { | 
 |       if (inf->terminal_state != target_terminal_state::is_ours) | 
 | 	{ | 
 | 	  gdb_assert (inf->pid != 0); | 
 |  | 
 | #ifndef _WIN32 | 
 | 	  kill (inf->pid, SIGINT); | 
 | #endif | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* If no inferior was resumed in the foreground, then how did the | 
 |      !is_ours assert above pass?  */ | 
 |   gdb_assert_not_reached ("no inferior resumed in the fg found"); | 
 | } | 
 |  | 
 | /* Per-inferior data key.  */ | 
 | static const registry<inferior>::key<terminal_info> inflow_inferior_data; | 
 |  | 
 | terminal_info::~terminal_info () | 
 | { | 
 |   xfree (ttystate); | 
 | } | 
 |  | 
 | /* Get the current svr4 data.  If none is found yet, add it now.  This | 
 |    function always returns a valid object.  */ | 
 |  | 
 | static struct terminal_info * | 
 | get_inflow_inferior_data (struct inferior *inf) | 
 | { | 
 |   struct terminal_info *info; | 
 |  | 
 |   info = inflow_inferior_data.get (inf); | 
 |   if (info == NULL) | 
 |     info = inflow_inferior_data.emplace (inf); | 
 |  | 
 |   return info; | 
 | } | 
 |  | 
 | /* This is a "inferior_exit" observer.  Releases the TERMINAL_INFO member | 
 |    of the inferior structure.  This field is private to inflow.c, and | 
 |    its type is opaque to the rest of GDB.  PID is the target pid of | 
 |    the inferior that is about to be removed from the inferior | 
 |    list.  */ | 
 |  | 
 | static void | 
 | inflow_inferior_exit (struct inferior *inf) | 
 | { | 
 |   inf->terminal_state = target_terminal_state::is_ours; | 
 |   inflow_inferior_data.clear (inf); | 
 | } | 
 |  | 
 | void | 
 | copy_terminal_info (struct inferior *to, struct inferior *from) | 
 | { | 
 |   struct terminal_info *tinfo_to, *tinfo_from; | 
 |  | 
 |   tinfo_to = get_inflow_inferior_data (to); | 
 |   tinfo_from = get_inflow_inferior_data (from); | 
 |  | 
 |   xfree (tinfo_to->ttystate); | 
 |  | 
 |   *tinfo_to = *tinfo_from; | 
 |  | 
 |   if (tinfo_from->ttystate) | 
 |     tinfo_to->ttystate | 
 |       = serial_copy_tty_state (stdin_serial, tinfo_from->ttystate); | 
 |  | 
 |   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); | 
 | } | 
 |  | 
 | void | 
 | child_terminal_info (struct target_ops *self, const char *args, int from_tty) | 
 | { | 
 |   struct inferior *inf; | 
 |   struct terminal_info *tinfo; | 
 |  | 
 |   if (!gdb_has_a_terminal ()) | 
 |     { | 
 |       gdb_printf (_("This GDB does not control a terminal.\n")); | 
 |       return; | 
 |     } | 
 |  | 
 |   if (inferior_ptid == null_ptid) | 
 |     return; | 
 |  | 
 |   inf = current_inferior (); | 
 |   tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 |   gdb_printf (_("Inferior's terminal status " | 
 | 		"(currently saved by GDB):\n")); | 
 |  | 
 |   /* First the fcntl flags.  */ | 
 |   { | 
 |     int flags; | 
 |  | 
 |     flags = tinfo->tflags; | 
 |  | 
 |     gdb_printf ("File descriptor flags = "); | 
 |  | 
 | #ifndef O_ACCMODE | 
 | #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) | 
 | #endif | 
 |     /* (O_ACCMODE) parens are to avoid Ultrix header file bug.  */ | 
 |     switch (flags & (O_ACCMODE)) | 
 |       { | 
 |       case O_RDONLY: | 
 | 	gdb_printf ("O_RDONLY"); | 
 | 	break; | 
 |       case O_WRONLY: | 
 | 	gdb_printf ("O_WRONLY"); | 
 | 	break; | 
 |       case O_RDWR: | 
 | 	gdb_printf ("O_RDWR"); | 
 | 	break; | 
 |       } | 
 |     flags &= ~(O_ACCMODE); | 
 |  | 
 | #ifdef O_NONBLOCK | 
 |     if (flags & O_NONBLOCK) | 
 |       gdb_printf (" | O_NONBLOCK"); | 
 |     flags &= ~O_NONBLOCK; | 
 | #endif | 
 |  | 
 | #if defined (O_NDELAY) | 
 |     /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will | 
 |        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) | 
 |       gdb_printf (" | O_NDELAY"); | 
 |     flags &= ~O_NDELAY; | 
 | #endif | 
 |  | 
 |     if (flags & O_APPEND) | 
 |       gdb_printf (" | O_APPEND"); | 
 |     flags &= ~O_APPEND; | 
 |  | 
 | #if defined (O_BINARY) | 
 |     if (flags & O_BINARY) | 
 |       gdb_printf (" | O_BINARY"); | 
 |     flags &= ~O_BINARY; | 
 | #endif | 
 |  | 
 |     if (flags) | 
 |       gdb_printf (" | 0x%x", flags); | 
 |     gdb_printf ("\n"); | 
 |   } | 
 |  | 
 | #ifdef HAVE_TERMIOS_H | 
 |   gdb_printf ("Process group = %d\n", (int) tinfo->process_group); | 
 | #endif | 
 |  | 
 |   serial_print_tty_state (stdin_serial, tinfo->ttystate, gdb_stdout); | 
 | } | 
 |  | 
 | /* 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 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 (std::string ttyname) | 
 | { | 
 |   /* Save the name for later, for determining whether we and the child | 
 |      are sharing a tty.  */ | 
 |   inferior_thisrun_terminal = std::move (ttyname); | 
 | } | 
 |  | 
 | #if !defined(__GO32__) && !defined(_WIN32) | 
 | /* If RESULT, assumed to be the return value from a system call, is | 
 |    negative, print the error message indicated by errno and exit. | 
 |    MSG should identify the operation that failed.  */ | 
 | static void | 
 | check_syscall (const char *msg, int result) | 
 | { | 
 |   if (result < 0) | 
 |     { | 
 |       gdb_printf (gdb_stderr, "%s:%s.\n", msg, | 
 | 		  safe_strerror (errno)); | 
 |       _exit (1); | 
 |     } | 
 | } | 
 | #endif | 
 |  | 
 | void | 
 | new_tty (void) | 
 | { | 
 |   if (inferior_thisrun_terminal.empty ()) | 
 |     return; | 
 | #if !defined(__GO32__) && !defined(_WIN32) | 
 |   int tty; | 
 |  | 
 | #ifdef TIOCNOTTY | 
 |   /* Disconnect the child process from our controlling terminal.  On some | 
 |      systems (SVR4 for example), this may cause a SIGTTOU, so temporarily | 
 |      ignore SIGTTOU.  */ | 
 |   tty = open ("/dev/tty", O_RDWR); | 
 |   if (tty >= 0) | 
 |     { | 
 |       scoped_ignore_sigttou ignore_sigttou; | 
 |  | 
 |       ioctl (tty, TIOCNOTTY, 0); | 
 |       close (tty); | 
 |     } | 
 | #endif | 
 |  | 
 |   /* Now open the specified new terminal.  */ | 
 |   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) | 
 |     { | 
 |       close (0); | 
 |       check_syscall ("dup'ing tty into fd 0", dup (tty)); | 
 |     } | 
 |   if (tty != 1) | 
 |     { | 
 |       close (1); | 
 |       check_syscall ("dup'ing tty into fd 1", dup (tty)); | 
 |     } | 
 |   if (tty != 2) | 
 |     { | 
 |       close (2); | 
 |       check_syscall ("dup'ing tty into fd 2", dup (tty)); | 
 |     } | 
 |  | 
 | #ifdef TIOCSCTTY | 
 |   /* Make tty our new controlling terminal.  */ | 
 |   if (ioctl (tty, TIOCSCTTY, 0) == -1) | 
 |     /* Mention GDB in warning because it will appear in the inferior's | 
 |        terminal instead of GDB's.  */ | 
 |     warning (_("GDB: Failed to set controlling terminal: %s"), | 
 | 	     safe_strerror (errno)); | 
 | #endif | 
 |  | 
 |   if (tty > 2) | 
 |     close (tty); | 
 | #endif /* !go32 && !win32 */ | 
 | } | 
 |  | 
 | /* 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 empty if it sharing the terminal with gdb.  */ | 
 |  | 
 | void | 
 | new_tty_postfork (void) | 
 | { | 
 |   /* Save the name for later, for determining whether we and the child | 
 |      are sharing a tty.  */ | 
 |  | 
 |   struct inferior *inf = current_inferior (); | 
 |   struct terminal_info *tinfo = get_inflow_inferior_data (inf); | 
 |  | 
 |   tinfo->run_terminal = std::move (inferior_thisrun_terminal); | 
 |   inferior_thisrun_terminal.clear (); | 
 | } | 
 |  | 
 |  | 
 | /* Call set_sigint_trap when you need to pass a signal on to an attached | 
 |    process when handling SIGINT.  */ | 
 |  | 
 | static void | 
 | pass_signal (int signo) | 
 | { | 
 | #ifndef _WIN32 | 
 |   kill (inferior_ptid.pid (), SIGINT); | 
 | #endif | 
 | } | 
 |  | 
 | static sighandler_t osig; | 
 | static int osig_set; | 
 |  | 
 | void | 
 | 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.empty ()) | 
 |     { | 
 |       osig = install_sigint_handler (pass_signal); | 
 |       osig_set = 1; | 
 |     } | 
 |   else | 
 |     osig_set = 0; | 
 | } | 
 |  | 
 | void | 
 | clear_sigint_trap (void) | 
 | { | 
 |   if (osig_set) | 
 |     { | 
 |       install_sigint_handler (osig); | 
 |       osig_set = 0; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* Create a new session if the inferior will run in a different tty. | 
 |    A session is UNIX's way of grouping processes that share a controlling | 
 |    terminal, so a new one is needed if the inferior terminal will be | 
 |    different from GDB's. | 
 |  | 
 |    Returns the session id of the new session, 0 if no session was created | 
 |    or -1 if an error occurred.  */ | 
 | pid_t | 
 | create_tty_session (void) | 
 | { | 
 | #ifdef HAVE_SETSID | 
 |   pid_t ret; | 
 |  | 
 |   if (!job_control || inferior_thisrun_terminal.empty ()) | 
 |     return 0; | 
 |  | 
 |   ret = setsid (); | 
 |   if (ret == -1) | 
 |     warning (_("Failed to create new terminal session: setsid: %s"), | 
 | 	     safe_strerror (errno)); | 
 |  | 
 |   return ret; | 
 | #else | 
 |   return 0; | 
 | #endif /* HAVE_SETSID */ | 
 | } | 
 |  | 
 | /* Get all the current tty settings (including whether we have a | 
 |    tty at all!).  We can't do this in _initialize_inflow because | 
 |    serial_fdopen() won't work until the serial_ops_list is | 
 |    initialized, but we don't want to do it lazily either, so | 
 |    that we can guarantee stdin_serial is opened if there is | 
 |    a terminal.  */ | 
 | void | 
 | initialize_stdin_serial (void) | 
 | { | 
 |   stdin_serial = serial_fdopen (0); | 
 | } | 
 |  | 
 | void _initialize_inflow (); | 
 | void | 
 | _initialize_inflow () | 
 | { | 
 |   add_info ("terminal", info_terminal_command, | 
 | 	    _("Print inferior's saved terminal status.")); | 
 |  | 
 |   /* OK, figure out whether we have job control.  */ | 
 |   have_job_control (); | 
 |  | 
 |   gdb::observers::inferior_exit.attach (inflow_inferior_exit, "inflow"); | 
 | } |