/* Low level interface to ptrace, for GDB when running under Unix.
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1986-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "gdbthread.h"
#include "observer.h"
-
-#include "gdb_string.h"
#include <signal.h>
#include <fcntl.h>
#include "gdb_select.h"
#include "inflow.h"
+#include "gdbcmd.h"
+#include "gdb_termios.h"
+#include "job-control.h"
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
static void pass_signal (int);
-static void terminal_ours_1 (int);
+static void child_terminal_ours_1 (int);
\f
/* Record terminal status separately for debugger and inferior. */
};
/* Our own tty state, which we restore every time we need to deal with
- the terminal. This is only set once, when GDB first starts. The
- settings of flags which readline saves and restores and
+ 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 *);
#ifdef PROCESS_GROUP_TYPE
we save our handlers in these two variables and set SIGINT and SIGQUIT
to SIG_IGN. */
-static void (*sigint_ours) ();
-static void (*sigquit_ours) ();
+static sighandler_t sigint_ours;
+static sighandler_t sigquit_ours;
/* 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
gdb_getpgrp (void)
{
int process_group = -1;
+
#ifdef HAVE_TERMIOS
process_group = tcgetpgrp (0);
#endif
}
#endif
-enum
- {
- yes, no, have_not_checked
- }
-gdb_has_a_terminal_flag = have_not_checked;
+/* See terminal.h. */
-/* Does GDB have a terminal (on stdin)? */
-int
-gdb_has_a_terminal (void)
+void
+set_initial_gdb_ttystate (void)
{
- switch (gdb_has_a_terminal_flag)
- {
- case yes:
- return 1;
- case no:
- return 0;
- case have_not_checked:
- /* Get all the current tty settings (including whether we have a
- tty at all!). Can't do this in _initialize_inflow because
- serial_fdopen() won't work until the serial_ops_list is
- initialized. */
+ /* 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
-
- gdb_has_a_terminal_flag = no;
- if (stdin_serial != NULL)
- {
- our_terminal_info.ttystate = serial_get_tty_state (stdin_serial);
-
- if (our_terminal_info.ttystate != NULL)
- {
- gdb_has_a_terminal_flag = yes;
#ifdef PROCESS_GROUP_TYPE
- our_terminal_info.process_group = gdb_getpgrp ();
+ our_terminal_info.process_group = gdb_getpgrp ();
#endif
- }
- }
-
- return gdb_has_a_terminal_flag == yes;
- default:
- /* "Can't happen". */
- return 0;
}
}
+/* 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) \
fprintf_unfiltered(gdb_stderr, "[%s failed in terminal_inferior: %s]\n", \
what, safe_strerror (errno))
-static void terminal_ours_1 (int);
-
/* Initialize the terminal settings we record for the inferior,
before we actually run the inferior. */
void
-terminal_init_inferior_with_pgrp (int pgrp)
+child_terminal_init_with_pgrp (int pgrp)
{
- if (gdb_has_a_terminal ())
- {
- struct inferior *inf = current_inferior ();
- struct terminal_info *tinfo = get_inflow_inferior_data (inf);
-
- /* We could just as well copy our_ttystate (if we felt like
- adding a new function serial_copy_tty_state()). */
- xfree (tinfo->ttystate);
- tinfo->ttystate = serial_get_tty_state (stdin_serial);
+ struct inferior *inf = current_inferior ();
+ struct terminal_info *tinfo = get_inflow_inferior_data (inf);
#ifdef PROCESS_GROUP_TYPE
- tinfo->process_group = pgrp;
+ /* Store the process group even without a terminal as it is used not
+ only to reset the tty foreground process group, but also to
+ interrupt the inferior. */
+ tinfo->process_group = pgrp;
#endif
+ if (gdb_has_a_terminal ())
+ {
+ xfree (tinfo->ttystate);
+ tinfo->ttystate = serial_copy_tty_state (stdin_serial,
+ initial_gdb_ttystate);
+
/* Make sure that next time we call terminal_inferior (which will be
before the program runs, as it needs to be), we install the new
process group. */
and gdb must be able to restore it correctly. */
void
-terminal_save_ours (void)
+gdb_save_tty_state (void)
{
if (gdb_has_a_terminal ())
{
- /* We could just as well copy our_ttystate (if we felt like adding
- a new function serial_copy_tty_state). */
xfree (our_terminal_info.ttystate);
our_terminal_info.ttystate = serial_get_tty_state (stdin_serial);
}
}
void
-terminal_init_inferior (void)
+child_terminal_init (struct target_ops *self)
{
#ifdef PROCESS_GROUP_TYPE
- /* This is for Lynx, and should be cleaned up by having Lynx be a separate
- debugging target with a version of target_terminal_init_inferior which
- passes in the process group to a generic routine which does all the work
- (and the non-threaded child_terminal_init_inferior can just pass in
- inferior_ptid to the same routine). */
+ /* This is for Lynx, and should be cleaned up by having Lynx be a
+ separate debugging target with a version of target_terminal_init
+ which passes in the process group to a generic routine which does
+ all the work (and the non-threaded child_terminal_init can just
+ pass in inferior_ptid to the same routine). */
/* We assume INFERIOR_PID is also the child's process group. */
- terminal_init_inferior_with_pgrp (PIDGET (inferior_ptid));
+ child_terminal_init_with_pgrp (ptid_get_pid (inferior_ptid));
#endif /* PROCESS_GROUP_TYPE */
}
/* Put the inferior's terminal settings into effect.
- This is preparation for starting or resuming the inferior. */
+ This is preparation for starting or resuming the inferior.
+
+ 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 remove stdin
+ from the event loop). E.g., see linux_nat_terminal_inferior. */
void
-terminal_inferior (void)
+child_terminal_inferior (struct target_ops *self)
{
struct inferior *inf;
struct terminal_info *tinfo;
if (!job_control)
{
- sigint_ours = (void (*)()) signal (SIGINT, SIG_IGN);
+ sigint_ours = signal (SIGINT, SIG_IGN);
#ifdef SIGQUIT
- sigquit_ours = (void (*)()) signal (SIGQUIT, SIG_IGN);
+ sigquit_ours = signal (SIGQUIT, SIG_IGN);
#endif
}
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. */
+ 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
-terminal_ours_for_output (void)
+child_terminal_ours_for_output (struct target_ops *self)
{
- terminal_ours_1 (1);
+ child_terminal_ours_1 (1);
}
/* Put our terminal settings into effect.
First record the inferior's terminal settings
- so they can be restored properly later. */
+ 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
-terminal_ours (void)
+child_terminal_ours (struct target_ops *self)
{
- terminal_ours_1 (0);
+ child_terminal_ours_1 (0);
}
/* output_only is not used, and should not be used unless we introduce
flags. */
static void
-terminal_ours_1 (int output_only)
+child_terminal_ours_1 (int output_only)
{
struct inferior *inf;
struct terminal_info *tinfo;
if (tinfo->run_terminal != NULL || gdb_has_a_terminal () == 0)
return;
-
+ else
{
#ifdef SIGTTOU
/* Ignore this signal since it will happen when we try to set the
pgrp. */
- void (*osigttou) () = NULL;
+ sighandler_t osigttou = NULL;
#endif
- int result;
+ int result ATTRIBUTE_UNUSED;
#ifdef SIGTTOU
if (job_control)
- osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
+ osigttou = signal (SIGTTOU, SIG_IGN);
#endif
xfree (tinfo->ttystate);
mode, to avoid flushing input. We need to do the same thing
regardless of output_only, because we don't have separate
terminal_is_ours and terminal_is_ours_for_output flags. It's OK,
- though, since readline will deal with raw mode when/if it needs to.
- */
+ though, since readline will deal with raw mode when/if it needs
+ to. */
serial_noflush_set_tty_state (stdin_serial, our_terminal_info.ttystate,
tinfo->ttystate);
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 terminal_ours: %s]\n",
+ fprintf_unfiltered (gdb_stderr,
+ "[tcsetpgrp failed in child_terminal_ours: %s]\n",
safe_strerror (errno));
#endif
#endif /* termios */
static void
inflow_inferior_data_cleanup (struct inferior *inf, void *arg)
{
- struct terminal_info *info;
+ struct terminal_info *info = (struct terminal_info *) arg;
- info = inferior_data (inf, inflow_inferior_data);
- if (info != NULL)
- {
- xfree (info->run_terminal);
- xfree (info);
- }
+ xfree (info->run_terminal);
+ xfree (info->ttystate);
+ xfree (info);
}
/* Get the current svr4 data. If none is found yet, add it now. This
{
struct terminal_info *info;
- info = inferior_data (inf, inflow_inferior_data);
+ info = (struct terminal_info *) inferior_data (inf, inflow_inferior_data);
if (info == NULL)
{
- info = XZALLOC (struct terminal_info);
+ info = XCNEW (struct terminal_info);
set_inferior_data (inf, inflow_inferior_data, info);
}
{
struct terminal_info *info;
- info = inferior_data (inf, inflow_inferior_data);
+ 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);
}
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);
}
void
-term_info (char *arg, int from_tty)
+info_terminal_command (char *arg, int from_tty)
{
target_terminal_info (arg, from_tty);
}
void
-child_terminal_info (char *args, int from_tty)
+child_terminal_info (struct target_ops *self, const char *args, int from_tty)
{
struct inferior *inf;
struct terminal_info *tinfo;
inf = current_inferior ();
tinfo = get_inflow_inferior_data (inf);
- printf_filtered (_("Inferior's terminal status (currently saved by GDB):\n"));
+ printf_filtered (_("Inferior's terminal status "
+ "(currently saved by GDB):\n"));
/* First the fcntl flags. */
{
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
- /* (O_ACCMODE) parens are to avoid Ultrix header file bug */
+ /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */
switch (flags & (O_ACCMODE))
{
case O_RDONLY:
#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. */
+ ignore SIGTTOU. */
tty = open ("/dev/tty", O_RDWR);
if (tty > 0)
{
- void (*osigttou) ();
+ sighandler_t osigttou;
- osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
+ osigttou = signal (SIGTTOU, SIG_IGN);
ioctl (tty, TIOCNOTTY, 0);
close (tty);
signal (SIGTTOU, osigttou);
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",
+ warning (_("GDB: Failed to set controlling terminal: %s"),
safe_strerror (errno));
#endif
\f
/* Call set_sigint_trap when you need to pass a signal on to an attached
- process when handling SIGINT */
+ process when handling SIGINT. */
static void
pass_signal (int signo)
{
#ifndef _WIN32
- kill (PIDGET (inferior_ptid), SIGINT);
+ kill (ptid_get_pid (inferior_ptid), SIGINT);
#endif
}
-static void (*osig) ();
+static sighandler_t osig;
static int osig_set;
void
if (inf->attach_flag || tinfo->run_terminal)
{
- osig = (void (*)()) signal (SIGINT, pass_signal);
+ osig = signal (SIGINT, pass_signal);
osig_set = 1;
}
else
ret = setsid ();
if (ret == -1)
- warning ("Failed to create new terminal session: setsid: %s",
+ warning (_("Failed to create new terminal session: setsid: %s"),
safe_strerror (errno));
return ret;
#endif /* HAVE_SETSID */
}
-/* This is here because this is where we figure out whether we (probably)
- have job control. Just using job_control only does part of it because
- setpgid or setpgrp might not exist on a system without job control.
- It might be considered misplaced (on the other hand, process groups and
- job control are closely related to ttys).
-
- For a more clean implementation, in libiberty, put a setpgid which merely
- calls setpgrp and a setpgrp which does nothing (any system with job control
- will have one or the other). */
-int
-gdb_setpgid (void)
-{
- int retval = 0;
-
- if (job_control)
- {
-#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
-#ifdef HAVE_SETPGID
- /* The call setpgid (0, 0) is supposed to work and mean the same
- thing as this, but on Ultrix 4.2A it fails with EPERM (and
- setpgid (getpid (), getpid ()) succeeds). */
- retval = setpgid (getpid (), getpid ());
-#else
-#ifdef HAVE_SETPGRP
-#ifdef SETPGRP_VOID
- retval = setpgrp ();
-#else
- retval = setpgrp (getpid (), getpid ());
-#endif
-#endif /* HAVE_SETPGRP */
-#endif /* HAVE_SETPGID */
-#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
- }
-
- return retval;
-}
-
/* 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
void
_initialize_inflow (void)
{
- add_info ("terminal", term_info,
+ add_info ("terminal", info_terminal_command,
_("Print inferior's saved terminal status."));
terminal_is_ours = 1;
- /* OK, figure out whether we have job control. If neither termios nor
- sgtty (i.e. termio or go32), leave job_control 0. */
-
-#if defined (HAVE_TERMIOS)
- /* Do all systems with termios have the POSIX way of identifying job
- control? I hope so. */
-#ifdef _POSIX_JOB_CONTROL
- job_control = 1;
-#else
-#ifdef _SC_JOB_CONTROL
- job_control = sysconf (_SC_JOB_CONTROL);
-#else
- job_control = 0; /* have to assume the worst */
-#endif /* _SC_JOB_CONTROL */
-#endif /* _POSIX_JOB_CONTROL */
-#endif /* HAVE_TERMIOS */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
- job_control = 1;
-#else
- job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
+ /* OK, figure out whether we have job control. */
+ have_job_control ();
observer_attach_inferior_exit (inflow_inferior_exit);
inflow_inferior_data
- = register_inferior_data_with_cleanup (inflow_inferior_data_cleanup);
+ = register_inferior_data_with_cleanup (NULL, inflow_inferior_data_cleanup);
}