/* Top level stuff for GDB, the GNU debugger.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
#include "cli/cli-script.h" /* for reset_command_nest_depth */
#include "main.h"
#include "gdbthread.h"
-#include "observer.h"
+#include "observable.h"
#include "continuations.h"
#include "gdbcmd.h" /* for dont_repeat() */
#include "annotate.h"
#include "maint.h"
-#include "buffer.h"
+#include "common/buffer.h"
#include "ser-event.h"
#include "gdb_select.h"
/* readline defines this. */
#undef savestring
-static char *top_level_prompt (void);
+static std::string top_level_prompt ();
/* Signal handlers. */
#ifdef SIGQUIT
static void async_disconnect (gdb_client_data);
#endif
static void async_float_handler (gdb_client_data);
-#ifdef STOP_SIGNAL
-static void async_stop_sig (gdb_client_data);
+#ifdef SIGTSTP
+static void async_sigtstp_handler (gdb_client_data);
#endif
static void async_sigterm_handler (gdb_client_data arg);
static struct async_signal_handler *sigquit_token;
#endif
static struct async_signal_handler *sigfpe_token;
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
static struct async_signal_handler *sigtstp_token;
#endif
static struct async_signal_handler *async_sigterm_token;
sjlj-based TRY/CATCH mechanism, which knows to handle multiple
levels of active setjmp/longjmp frames, needed in order to handle
the readline callback recursing, as happens with e.g., secondary
- prompts / queries, through gdb_readline_wrapper. */
+ prompts / queries, through gdb_readline_wrapper. This must be
+ noexcept in order to avoid problems with mixing sjlj and
+ (sjlj-based) C++ exceptions. */
-static void
-gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
+static struct gdb_exception
+gdb_rl_callback_read_char_wrapper_noexcept () noexcept
{
struct gdb_exception gdb_expt = exception_none;
}
END_CATCH_SJLJ
+ return gdb_expt;
+}
+
+static void
+gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
+{
+ struct gdb_exception gdb_expt
+ = gdb_rl_callback_read_char_wrapper_noexcept ();
+
/* Rethrow using the normal EH mechanism. */
if (gdb_expt.reason < 0)
throw_exception (gdb_expt);
/* GDB's readline callback handler. Calls the current INPUT_HANDLER,
and propagates GDB exceptions/errors thrown from INPUT_HANDLER back
- across readline. See gdb_rl_callback_read_char_wrapper. */
+ across readline. See gdb_rl_callback_read_char_wrapper. This must
+ be noexcept in order to avoid problems with mixing sjlj and
+ (sjlj-based) C++ exceptions. */
static void
-gdb_rl_callback_handler (char *rl)
+gdb_rl_callback_handler (char *rl) noexcept
{
struct gdb_exception gdb_rl_expt = exception_none;
struct ui *ui = current_ui;
TRY
{
- ui->input_handler (rl);
+ ui->input_handler (gdb::unique_xmalloc_ptr<char> (rl));
}
CATCH (ex, RETURN_MASK_ALL)
{
void
display_gdb_prompt (const char *new_prompt)
{
- char *actual_gdb_prompt = NULL;
- struct cleanup *old_chain;
+ std::string actual_gdb_prompt;
annotate_display_prompt ();
/* Reset the nesting depth used when trace-commands is set. */
reset_command_nest_depth ();
- old_chain = make_cleanup (free_current_contents, &actual_gdb_prompt);
-
/* Do not call the python hook on an explicit prompt change as
passed to this function, as this forms a secondary/local prompt,
IE, displayed but not set. */
if (current_ui->command_editing)
gdb_rl_callback_handler_remove ();
- do_cleanups (old_chain);
return;
}
else if (ui->prompt_state == PROMPT_NEEDED)
}
}
else
- actual_gdb_prompt = xstrdup (new_prompt);
+ actual_gdb_prompt = new_prompt;
if (current_ui->command_editing)
{
gdb_rl_callback_handler_remove ();
- gdb_rl_callback_handler_install (actual_gdb_prompt);
+ gdb_rl_callback_handler_install (actual_gdb_prompt.c_str ());
}
/* new_prompt at this point can be the top of the stack or the one
passed in. It can't be NULL. */
/* Don't use a _filtered function here. It causes the assumed
character position to be off, since the newline we read from
the user is not accounted for. */
- fputs_unfiltered (actual_gdb_prompt, gdb_stdout);
+ fputs_unfiltered (actual_gdb_prompt.c_str (), gdb_stdout);
gdb_flush (gdb_stdout);
}
-
- do_cleanups (old_chain);
}
/* Return the top level prompt, as specified by "set prompt", possibly
overriden by the python gdb.prompt_hook hook, and then composed
- with the prompt prefix and suffix (annotations). The caller is
- responsible for freeing the returned string. */
+ with the prompt prefix and suffix (annotations). */
-static char *
+static std::string
top_level_prompt (void)
{
char *prompt;
/* Give observers a chance of changing the prompt. E.g., the python
`gdb.prompt_hook' is installed as an observer. */
- observer_notify_before_prompt (get_prompt ());
+ gdb::observers::before_prompt.notify (get_prompt ());
prompt = get_prompt ();
beginning. */
const char suffix[] = "\n\032\032prompt\n";
- return concat (prefix, prompt, suffix, (char *) NULL);
+ return std::string (prefix) + prompt + suffix;
}
- return xstrdup (prompt);
+ return prompt;
}
/* See top.h. */
else
{
/* Simply delete the UI. */
- delete_ui (ui);
+ delete ui;
}
}
else
if (ui->prompt_state == PROMPT_BLOCKED)
{
- target_terminal_ours ();
+ target_terminal::ours ();
ui_register_input_event_handler (ui);
ui->prompt_state = PROMPT_NEEDED;
}
a whole command. */
void
-command_handler (char *command)
+command_handler (const char *command)
{
struct ui *ui = current_ui;
- struct cleanup *stat_chain;
- char *c;
+ const char *c;
if (ui->instream == ui->stdin_stream)
reinitialize_more_filter ();
- stat_chain = make_command_stats_cleanup (1);
+ scoped_command_stats stat_reporter (true);
/* Do not execute commented lines. */
for (c = command; *c == ' ' || *c == '\t'; c++)
/* Do any commands attached to breakpoint we stopped at. */
bpstat_do_actions ();
}
-
- do_cleanups (stat_chain);
}
/* Append RL, an input line returned by readline or one of its
emulations, to CMD_LINE_BUFFER. Returns the command line if we
have a whole command line ready to be processed by the command
interpreter or NULL if the command line isn't complete yet (input
- line ends in a backslash). Takes ownership of RL. */
+ line ends in a backslash). */
static char *
-command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl)
+command_line_append_input_line (struct buffer *cmd_line_buffer, const char *rl)
{
char *cmd;
size_t len;
cmd = cmd_line_buffer->buffer;
}
- /* Allocated in readline. */
- xfree (rl);
-
return cmd;
}
char *
handle_line_of_input (struct buffer *cmd_line_buffer,
- char *rl, int repeat, char *annotation_suffix)
+ const char *rl, int repeat,
+ const char *annotation_suffix)
{
struct ui *ui = current_ui;
int from_tty = ui->instream == ui->stdin_stream;
}
#define SERVER_COMMAND_PREFIX "server "
- if (startswith (cmd, SERVER_COMMAND_PREFIX))
+ server_command = startswith (cmd, SERVER_COMMAND_PREFIX);
+ if (server_command)
{
/* Note that we don't set `saved_command_line'. Between this
and the check in dont_repeat, this insures that repeating
/* Do history expansion if that is wished. */
if (history_expansion_p && from_tty && input_interactive_p (current_ui))
{
- char *history_value;
+ char *cmd_expansion;
int expanded;
- expanded = history_expand (cmd, &history_value);
+ expanded = history_expand (cmd, &cmd_expansion);
+ gdb::unique_xmalloc_ptr<char> history_value (cmd_expansion);
if (expanded)
{
size_t len;
/* Print the changes. */
- printf_unfiltered ("%s\n", history_value);
+ printf_unfiltered ("%s\n", history_value.get ());
/* If there was an error, call this function again. */
if (expanded < 0)
- {
- xfree (history_value);
- return cmd;
- }
+ return cmd;
/* history_expand returns an allocated string. Just replace
our buffer with it. */
- len = strlen (history_value);
+ len = strlen (history_value.get ());
xfree (buffer_finish (cmd_line_buffer));
- cmd_line_buffer->buffer = history_value;
+ cmd_line_buffer->buffer = history_value.get ();
cmd_line_buffer->buffer_size = len + 1;
- cmd = history_value;
+ cmd = history_value.release ();
}
}
function. */
void
-command_line_handler (char *rl)
+command_line_handler (gdb::unique_xmalloc_ptr<char> &&rl)
{
struct buffer *line_buffer = get_command_line_buffer ();
struct ui *ui = current_ui;
char *cmd;
- cmd = handle_line_of_input (line_buffer, rl, 1, "prompt");
+ cmd = handle_line_of_input (line_buffer, rl.get (), 1, "prompt");
if (cmd == (char *) EOF)
{
/* stdin closed. The connection with the terminal is gone.
buffer_grow_char (&line_buffer, '\0');
result = buffer_finish (&line_buffer);
- ui->input_handler (result);
+ ui->input_handler (gdb::unique_xmalloc_ptr<char> (result));
}
\f
sigfpe_token =
create_async_signal_handler (async_float_handler, NULL);
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
sigtstp_token =
- create_async_signal_handler (async_stop_sig, NULL);
+ create_async_signal_handler (async_sigtstp_handler, NULL);
#endif
}
{
if (check_quit_flag ())
{
- if (target_terminal_is_ours ())
+ if (target_terminal::is_ours ())
quit ();
else
target_pass_ctrlc ();
/* See defs.h. */
quit_handler_ftype *quit_handler = default_quit_handler;
-/* Data for make_cleanup_override_quit_handler. Wrap the previous
- handler pointer in a data struct because it's not portable to cast
- a function pointer to a data pointer, which is what make_cleanup
- expects. */
-struct quit_handler_cleanup_data
-{
- /* The previous quit handler. */
- quit_handler_ftype *prev_handler;
-};
-
-/* Cleanup call that restores the previous quit handler. */
-
-static void
-restore_quit_handler (void *arg)
-{
- struct quit_handler_cleanup_data *data
- = (struct quit_handler_cleanup_data *) arg;
-
- quit_handler = data->prev_handler;
-}
-
-/* Destructor for the quit handler cleanup. */
-
-static void
-restore_quit_handler_dtor (void *arg)
-{
- xfree (arg);
-}
-
-/* See defs.h. */
-
-struct cleanup *
-make_cleanup_override_quit_handler (quit_handler_ftype *new_quit_handler)
-{
- struct cleanup *old_chain;
- struct quit_handler_cleanup_data *data;
-
- data = XNEW (struct quit_handler_cleanup_data);
- data->prev_handler = quit_handler;
- old_chain = make_cleanup_dtor (restore_quit_handler, data,
- restore_quit_handler_dtor);
- quit_handler = new_quit_handler;
- return old_chain;
-}
-
/* Handle a SIGINT. */
void
}
#endif
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
void
-handle_stop_sig (int sig)
+handle_sigtstp (int sig)
{
mark_async_signal_handler (sigtstp_token);
- signal (sig, handle_stop_sig);
+ signal (sig, handle_sigtstp);
}
static void
-async_stop_sig (gdb_client_data arg)
+async_sigtstp_handler (gdb_client_data arg)
{
char *prompt = get_prompt ();
-#if STOP_SIGNAL == SIGTSTP
signal (SIGTSTP, SIG_DFL);
#if HAVE_SIGPROCMASK
{
sigsetmask (0);
#endif
raise (SIGTSTP);
- signal (SIGTSTP, handle_stop_sig);
-#else
- signal (STOP_SIGNAL, handle_stop_sig);
-#endif
+ signal (SIGTSTP, handle_sigtstp);
printf_unfiltered ("%s", prompt);
gdb_flush (gdb_stdout);
nothing. */
dont_repeat ();
}
-#endif /* STOP_SIGNAL */
+#endif /* SIGTSTP */
/* Tell the event loop what to do if SIGFPE is received.
See event-signal.c. */
mess it up here. The sync stuff should really go away over
time. */
if (!batch_silent)
- gdb_stdout = stdio_fileopen (ui->outstream);
- gdb_stderr = stderr_fileopen (ui->errstream);
+ gdb_stdout = new stdio_file (ui->outstream);
+ gdb_stderr = new stderr_file (ui->errstream);
gdb_stdlog = gdb_stderr; /* for moment */
gdb_stdtarg = gdb_stderr; /* for moment */
gdb_stdtargerr = gdb_stderr; /* for moment */