/* Low level interface to ptrace, for GDB when running under Unix.
- Copyright (C) 1986-2019 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>
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
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
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
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
#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. */
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)
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));
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 */
}
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;
}
}
/* 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
{
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;
}
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
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
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);
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;
}
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. */
{
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)
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
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);
\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)
void
new_tty (void)
{
- if (inferior_thisrun_terminal == 0)
+ if (inferior_thisrun_terminal.empty ())
return;
#if !defined(__GO32__) && !defined(_WIN32)
int tty;
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;
#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)
/* 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)
/* 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
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;
#ifdef HAVE_SETSID
pid_t ret;
- if (!job_control || inferior_thisrun_terminal == 0)
+ if (!job_control || inferior_thisrun_terminal.empty ())
return 0;
ret = setsid ();
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."));
/* 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");
}