mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-09 04:21:49 +08:00
1e28eebbbc
PR mi/15811 points out that "source"ing a file that uses interpreter-exec will put gdb in a weird state, where the CLI stops working. The bug is that tui_interp::suspend does not unregister the event file descriptor. The test case is from Andrew Burgess. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=15811
183 lines
4.5 KiB
C
183 lines
4.5 KiB
C
/* TUI Interpreter definitions for GDB, the GNU debugger.
|
|
|
|
Copyright (C) 2003-2022 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 "defs.h"
|
|
#include "cli/cli-interp.h"
|
|
#include "interps.h"
|
|
#include "top.h"
|
|
#include "event-top.h"
|
|
#include "gdbsupport/event-loop.h"
|
|
#include "ui-out.h"
|
|
#include "cli-out.h"
|
|
#include "tui/tui-data.h"
|
|
#include "tui/tui-win.h"
|
|
#include "tui/tui.h"
|
|
#include "tui/tui-io.h"
|
|
#include "infrun.h"
|
|
#include "observable.h"
|
|
#include "gdbthread.h"
|
|
#include "inferior.h"
|
|
#include "main.h"
|
|
|
|
/* Set to true when the TUI mode must be activated when we first start
|
|
gdb. */
|
|
static bool tui_start_enabled = false;
|
|
|
|
class tui_interp final : public cli_interp_base
|
|
{
|
|
public:
|
|
explicit tui_interp (const char *name)
|
|
: cli_interp_base (name)
|
|
{}
|
|
|
|
void init (bool top_level) override;
|
|
void resume () override;
|
|
void suspend () override;
|
|
gdb_exception exec (const char *command_str) override;
|
|
ui_out *interp_ui_out () override;
|
|
};
|
|
|
|
/* Cleanup the tui before exiting. */
|
|
|
|
static void
|
|
tui_exit (void)
|
|
{
|
|
/* Disable the tui. Curses mode is left leaving the screen in a
|
|
clean state (see endwin()). */
|
|
tui_disable ();
|
|
}
|
|
|
|
/* These implement the TUI interpreter. */
|
|
|
|
void
|
|
tui_interp::init (bool top_level)
|
|
{
|
|
/* Install exit handler to leave the screen in a good shape. */
|
|
atexit (tui_exit);
|
|
|
|
tui_initialize_io ();
|
|
if (gdb_stdout->isatty ())
|
|
{
|
|
tui_ensure_readline_initialized ();
|
|
|
|
/* This installs the SIGWINCH signal handler. The handler needs to do
|
|
readline calls (to rl_resize_terminal), so it must not be installed
|
|
unless readline is properly initialized. */
|
|
tui_initialize_win ();
|
|
}
|
|
}
|
|
|
|
/* Used as the command handler for the tui. */
|
|
|
|
static void
|
|
tui_command_line_handler (gdb::unique_xmalloc_ptr<char> &&rl)
|
|
{
|
|
/* When a tui enabled GDB is running in either tui mode or cli mode then
|
|
it is always the tui interpreter that is in use. As a result we end
|
|
up in here even in standard cli mode.
|
|
|
|
We only need to do any special actions when the tui is in use
|
|
though. When the tui is active the users return is not echoed to the
|
|
screen as a result the display will not automatically move us to the
|
|
next line. Here we manually insert a newline character and move the
|
|
cursor. */
|
|
if (tui_active)
|
|
tui_inject_newline_into_command_window ();
|
|
|
|
/* Now perform GDB's standard CLI command line handling. */
|
|
command_line_handler (std::move (rl));
|
|
}
|
|
|
|
void
|
|
tui_interp::resume ()
|
|
{
|
|
struct ui *ui = current_ui;
|
|
struct ui_file *stream;
|
|
|
|
/* gdb_setup_readline will change gdb_stdout. If the TUI was
|
|
previously writing to gdb_stdout, then set it to the new
|
|
gdb_stdout afterwards. */
|
|
|
|
stream = tui_old_uiout->set_stream (gdb_stdout);
|
|
if (stream != gdb_stdout)
|
|
{
|
|
tui_old_uiout->set_stream (stream);
|
|
stream = NULL;
|
|
}
|
|
|
|
gdb_setup_readline (1);
|
|
|
|
ui->input_handler = tui_command_line_handler;
|
|
|
|
if (stream != NULL)
|
|
tui_old_uiout->set_stream (gdb_stdout);
|
|
|
|
if (tui_start_enabled)
|
|
tui_enable ();
|
|
}
|
|
|
|
void
|
|
tui_interp::suspend ()
|
|
{
|
|
gdb_disable_readline ();
|
|
tui_start_enabled = tui_active;
|
|
tui_disable ();
|
|
}
|
|
|
|
ui_out *
|
|
tui_interp::interp_ui_out ()
|
|
{
|
|
if (tui_active)
|
|
return tui_out;
|
|
else
|
|
return tui_old_uiout;
|
|
}
|
|
|
|
gdb_exception
|
|
tui_interp::exec (const char *command_str)
|
|
{
|
|
internal_error (__FILE__, __LINE__, _("tui_exec called"));
|
|
}
|
|
|
|
|
|
/* Factory for TUI interpreters. */
|
|
|
|
static struct interp *
|
|
tui_interp_factory (const char *name)
|
|
{
|
|
return new tui_interp (name);
|
|
}
|
|
|
|
void _initialize_tui_interp ();
|
|
void
|
|
_initialize_tui_interp ()
|
|
{
|
|
interp_factory_register (INTERP_TUI, tui_interp_factory);
|
|
|
|
if (interpreter_p == INTERP_TUI)
|
|
tui_start_enabled = true;
|
|
|
|
if (interpreter_p == INTERP_CONSOLE)
|
|
interpreter_p = INTERP_TUI;
|
|
|
|
/* There are no observers here because the CLI interpreter's
|
|
observers work for the TUI interpreter as well. See
|
|
cli-interp.c. */
|
|
}
|