Make exceptions use std::string and be self-managing

This changes the exception's "message" member to be a shared_ptr
wrapping a std::string.  This allows removing the stack of exception
messages, because now exceptions will self-destruct when needed.  This
also adds a noexcept copy constructor and operator= to gdb_exception,
plus a "what" method.

gdb/ChangeLog
2019-04-08  Tom Tromey  <tom@tromey.com>

	* xml-support.c (gdb_xml_parser::parse): Update.
	* x86-linux-nat.c (x86_linux_nat_target::enable_btrace): Update.
	* value.c (show_convenience): Update.
	* unittests/cli-utils-selftests.c (test_number_or_range_parser)
	(test_parse_flags_qcs): Update.
	* thread.c (thr_try_catch_cmd): Update.
	* target.c (target_translate_tls_address): Update.
	* stack.c (print_frame_arg, read_frame_local, read_frame_arg)
	(info_frame_command_core, frame_apply_command_count): Update.
	* rust-exp.y (rust_lex_exception_test): Update.
	* riscv-tdep.c (riscv_print_one_register_info): Update.
	* remote.c (remote_target::enable_btrace): Update.
	* record-btrace.c (record_btrace_enable_warn): Update.
	* python/py-utils.c (gdbpy_convert_exception): Update.
	* printcmd.c (do_one_display, print_variable_and_value): Update.
	* mi/mi-main.c (mi_print_exception): Update.
	* mi/mi-interp.c (mi_cmd_interpreter_exec): Use SCOPE_EXIT.
	* mi/mi-cmd-stack.c (list_arg_or_local): Update.
	* linux-nat.c (linux_nat_target::attach): Update.
	* linux-fork.c (class scoped_switch_fork_info): Update.
	* infrun.c (displaced_step_prepare): Update.
	* infcall.c (call_function_by_hand_dummy): Update.
	* guile/scm-exception.c (gdbscm_scm_from_gdb_exception): Update.
	* gnu-v3-abi.c (print_one_vtable): Update.
	* frame.c (get_prev_frame_always): Update.
	* f-valprint.c (info_common_command_for_block): Update.
	* exec.c (try_open_exec_file): Update.
	* exceptions.c (print_exception, exception_print)
	(exception_fprintf, exception_print_same): Update.
	* dwarf2-frame.c (dwarf2_build_frame_info): Update.
	* dwarf-index-cache.c (index_cache::store)
	(index_cache::lookup_gdb_index): Update.
	* darwin-nat.c (maybe_cache_shell): Update.
	* cp-valprint.c (cp_print_value_fields): Update.
	* compile/compile-cplus-symbols.c (gcc_cplus_convert_symbol)
	(gcc_cplus_symbol_address): Update.
	* compile/compile-c-symbols.c (gcc_convert_symbol)
	(gcc_symbol_address, generate_c_for_for_one_variable): Update.
	* common/selftest.c: Update.
	* common/common-exceptions.h (struct gdb_exception) <message>: Now
	a std::string.
	(exception_try_scope_entry, exception_try_scope_exit): Don't
	declare.
	(struct exception_try_scope): Remove.
	(TRY): Don't use exception_try_scope.
	(struct gdb_exception): Add constructor, operator=.
	<what>: New method.
	(struct gdb_exception_RETURN_MASK_ALL)
	(struct gdb_exception_RETURN_MASK_ERROR)
	(struct gdb_exception_RETURN_MASK_QUIT): Add constructor.
	(struct gdb_quit_bad_alloc): Update.
	* common/common-exceptions.c (exception_none): Change
	initializer.
	(struct catcher) <state, exception>: Initialize inline.
	<prev>: Remove member.
	(current_catcher): Remove.
	(catchers): New global.
	(exceptions_state_mc_init): Simplify.
	(catcher_pop): Remove.
	(exceptions_state_mc, exceptions_state_mc_catch): Update.
	(try_scope_depth, exception_try_scope_entry)
	(exception_try_scope_exit): Remove.
	(throw_exception_sjlj): Update.
	(exception_messages, exception_messages_size): Remove.
	(throw_it): Simplify.
	(gdb_exception_sliced_copy): Remove.
	(throw_exception_cxx): Update.
	* cli/cli-script.c (script_from_file): Update.
	* breakpoint.c (insert_bp_location, update_breakpoint_locations):
	Update.
	* ada-valprint.c (ada_val_print): Update.
	* ada-lang.c (ada_to_fixed_type_1, ada_exception_name_addr)
	(create_excep_cond_exprs): Update.

gdb/gdbserver/ChangeLog
2019-04-08  Tom Tromey  <tom@tromey.com>

	* server.c (handle_btrace_general_set, handle_qxfer_btrace)
	(handle_qxfer_btrace_conf, detach_or_kill_for_exit_cleanup)
	(captured_main, main): Update.
	* gdbreplay.c (main): Update.
This commit is contained in:
Tom Tromey 2019-01-28 10:11:10 -07:00
parent c5c1011821
commit 3d6e9d2336
43 changed files with 253 additions and 245 deletions

View file

@ -19,8 +19,9 @@
#include "common-defs.h"
#include "common-exceptions.h"
#include <forward_list>
const struct gdb_exception exception_none = { (enum return_reason) 0, GDB_NO_ERROR, NULL };
const struct gdb_exception exception_none;
/* Possible catcher states. */
enum catcher_state {
@ -42,42 +43,21 @@ enum catcher_action {
struct catcher
{
enum catcher_state state;
enum catcher_state state = CATCHER_CREATED;
/* Jump buffer pointing back at the exception handler. */
jmp_buf buf;
/* Status buffer belonging to the exception handler. */
struct gdb_exception exception;
/* Back link. */
struct catcher *prev;
struct gdb_exception exception = exception_none;
};
/* Where to go for throw_exception(). */
static struct catcher *current_catcher;
static std::forward_list<struct catcher> catchers;
jmp_buf *
exceptions_state_mc_init (void)
exceptions_state_mc_init ()
{
struct catcher *new_catcher = XCNEW (struct catcher);
/* Start with no exception. */
new_catcher->exception = exception_none;
/* Push this new catcher on the top. */
new_catcher->prev = current_catcher;
current_catcher = new_catcher;
new_catcher->state = CATCHER_CREATED;
return &new_catcher->buf;
}
static void
catcher_pop (void)
{
struct catcher *old_catcher = current_catcher;
current_catcher = old_catcher->prev;
xfree (old_catcher);
catchers.emplace_front ();
return &catchers.front ().buf;
}
/* Catcher state machine. Returns non-zero if the m/c should be run
@ -86,14 +66,14 @@ catcher_pop (void)
static int
exceptions_state_mc (enum catcher_action action)
{
switch (current_catcher->state)
switch (catchers.front ().state)
{
case CATCHER_CREATED:
switch (action)
{
case CATCH_ITER:
/* Allow the code to run the catcher. */
current_catcher->state = CATCHER_RUNNING;
catchers.front ().state = CATCHER_RUNNING;
return 1;
default:
internal_error (__FILE__, __LINE__, _("bad state"));
@ -105,10 +85,10 @@ exceptions_state_mc (enum catcher_action action)
/* No error/quit has occured. */
return 0;
case CATCH_ITER_1:
current_catcher->state = CATCHER_RUNNING_1;
catchers.front ().state = CATCHER_RUNNING_1;
return 1;
case CATCH_THROWING:
current_catcher->state = CATCHER_ABORTING;
catchers.front ().state = CATCHER_ABORTING;
/* See also throw_exception. */
return 1;
default:
@ -121,10 +101,10 @@ exceptions_state_mc (enum catcher_action action)
/* The did a "break" from the inner while loop. */
return 0;
case CATCH_ITER_1:
current_catcher->state = CATCHER_RUNNING;
catchers.front ().state = CATCHER_RUNNING;
return 0;
case CATCH_THROWING:
current_catcher->state = CATCHER_ABORTING;
catchers.front ().state = CATCHER_ABORTING;
/* See also throw_exception. */
return 1;
default:
@ -152,8 +132,8 @@ int
exceptions_state_mc_catch (struct gdb_exception *exception,
int mask)
{
*exception = current_catcher->exception;
catcher_pop ();
*exception = std::move (catchers.front ().exception);
catchers.pop_front ();
if (exception->reason < 0)
{
@ -185,29 +165,6 @@ exceptions_state_mc_action_iter_1 (void)
return exceptions_state_mc (CATCH_ITER_1);
}
/* How many nested TRY blocks we have. See exception_messages and
throw_it. */
static int try_scope_depth;
/* Called on entry to a TRY scope. */
void *
exception_try_scope_entry (void)
{
++try_scope_depth;
return nullptr;
}
/* Called on exit of a TRY scope, either normal exit or exception
exit. */
void
exception_try_scope_exit (void *saved_state)
{
--try_scope_depth;
}
/* Called by the default catch block. IOW, we'll get here before
jumping out to the next outermost scope an exception if a GDB
exception is not caught. */
@ -218,14 +175,6 @@ exception_rethrow (void)
throw;
}
/* Copy the 'gdb_exception' portion of FROM to TO. */
static void
gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
{
*to = *from;
}
/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
void
@ -235,8 +184,8 @@ throw_exception_sjlj (struct gdb_exception exception)
that call via setjmp's return value. Note that REASON can't be
zero, by definition in common-exceptions.h. */
exceptions_state_mc (CATCH_THROWING);
current_catcher->exception = exception;
longjmp (current_catcher->buf, exception.reason);
catchers.front ().exception = exception;
longjmp (catchers.front ().buf, exception.reason);
}
/* Implementation of throw_exception that uses C++ try/catch. */
@ -246,16 +195,12 @@ throw_exception_cxx (struct gdb_exception exception)
{
if (exception.reason == RETURN_QUIT)
{
gdb_exception_RETURN_MASK_QUIT ex;
gdb_exception_sliced_copy (&ex, &exception);
gdb_exception_RETURN_MASK_QUIT ex (exception);
throw ex;
}
else if (exception.reason == RETURN_ERROR)
{
gdb_exception_RETURN_MASK_ERROR ex;
gdb_exception_sliced_copy (&ex, &exception);
gdb_exception_RETURN_MASK_ERROR ex (exception);
throw ex;
}
else
@ -268,52 +213,16 @@ throw_exception (struct gdb_exception exception)
throw_exception_cxx (exception);
}
/* A stack of exception messages.
This is needed to handle nested calls to throw_it: we don't want to
xfree space for a message before it's used.
This can happen if we throw an exception during a cleanup:
An outer TRY_CATCH may have an exception message it wants to print,
but while doing cleanups further calls to throw_it are made.
This is indexed by the size of the current_catcher list.
It is a dynamically allocated array so that we don't care how deeply
GDB nests its TRY_CATCHs. */
static char **exception_messages;
/* The number of currently allocated entries in exception_messages. */
static int exception_messages_size;
static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
throw_it (enum return_reason reason, enum errors error, const char *fmt,
va_list ap)
{
struct gdb_exception e;
char *new_message;
int depth = try_scope_depth;
gdb_assert (depth > 0);
/* Note: The new message may use an old message's text. */
new_message = xstrvprintf (fmt, ap);
if (depth > exception_messages_size)
{
int old_size = exception_messages_size;
exception_messages_size = depth + 10;
exception_messages = XRESIZEVEC (char *, exception_messages,
exception_messages_size);
memset (exception_messages + old_size, 0,
(exception_messages_size - old_size) * sizeof (char *));
}
xfree (exception_messages[depth - 1]);
exception_messages[depth - 1] = new_message;
/* Create the exception. */
e.reason = reason;
e.error = error;
e.message = new_message;
e.message.reset (new std::string (string_vprintf (fmt, ap)));
/* Throw the exception. */
throw_exception (e);