aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Benson <gbenson@redhat.com>2014-08-07 16:29:19 +0100
committerGary Benson <gbenson@redhat.com>2014-08-29 10:53:37 +0100
commitff55e1b54898ca4e2a90c005749505e33e32215c (patch)
tree445dd77a23a2d18135ab85c5bea45efeaa7e5ef2
parente9bcb6585201ab674d90d714295f63b40da41f16 (diff)
downloadgdb-ff55e1b54898ca4e2a90c005749505e33e32215c.zip
gdb-ff55e1b54898ca4e2a90c005749505e33e32215c.tar.gz
gdb-ff55e1b54898ca4e2a90c005749505e33e32215c.tar.bz2
Introduce common/common-exceptions.[ch]
This commit moves the exception throwing and catching code into gdb/common/. All exception printing code remains in gdb/exceptions.[ch]. gdb/ChangeLog: * common/common-exceptions.h: New file. * common/common-exceptions.c: Likewise. * Makefile.in (SFILES): Add common/common-exceptions.c. (HFILES_NO_SRCDIR): Add common/common-exceptions.h. (COMMON_OBS): Add common-exceptions.o. (common-exceptions.o): New rule. * exceptions.h (common-exceptions.h): Include. (gdb_setjmp.h): Do not include. (return_reason): Moved to common-exceptions.h. (enum return_reason): Likewise. (RETURN_MASK): Likewise. (typedef return_mask): Likewise. (enum errors): Likewise. (struct gdb_exception): Likewise. (exceptions_state_mc_init): Likewise. (exceptions_state_mc_action_iter): Likewise. (exceptions_state_mc_action_iter_1): Likewise. (TRY_CATCH): Likewise. (throw_exception): Likewise. (throw_verror): Likewise. (throw_vquit): Likewise. (throw_error): Likewise. (throw_quit): Likewise. * exceptions.c (enum catcher_state): Moved to common-exceptions.c. (enum catcher_action): Likewise. (struct catcher): Likewise. (current_catcher): Likewise. (catcher_list_size): Likewise. (exceptions_state_mc_init): Likewise. (catcher_pop): Likewise. (exceptions_state_mc): Likewise. (exceptions_state_mc_action_iter): Likewise. (exceptions_state_mc_action_iter_1): Likewise. (throw_exception): Likewise. (exception_messages): Likewise. (exception_messages_size): Likewise. (throw_it): Likewise. (throw_verror): Likewise. (throw_vquit): Likewise. (throw_error): Likewise. (throw_quit): Likewise. (prepare_to_throw_exception): New function. gdb/gdbserver/ChangeLog: * Makefile.in (SFILES): Add common/common-exceptions.c. (OBS): Add common-exceptions.o. (common-exceptions.o): New rule. * utils.c (prepare_to_throw_exception): New function.
-rw-r--r--gdb/ChangeLog45
-rw-r--r--gdb/Makefile.in12
-rw-r--r--gdb/common/common-exceptions.c308
-rw-r--r--gdb/common/common-exceptions.h185
-rw-r--r--gdb/exceptions.c282
-rw-r--r--gdb/exceptions.h154
-rw-r--r--gdb/gdbserver/ChangeLog7
-rw-r--r--gdb/gdbserver/Makefile.in7
-rw-r--r--gdb/gdbserver/utils.c8
9 files changed, 570 insertions, 438 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index fbe8e87..07f0c5e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,50 @@
2014-08-29 Gary Benson <gbenson@redhat.com>
+ * common/common-exceptions.h: New file.
+ * common/common-exceptions.c: Likewise.
+ * Makefile.in (SFILES): Add common/common-exceptions.c.
+ (HFILES_NO_SRCDIR): Add common/common-exceptions.h.
+ (COMMON_OBS): Add common-exceptions.o.
+ (common-exceptions.o): New rule.
+ * exceptions.h (common-exceptions.h): Include.
+ (gdb_setjmp.h): Do not include.
+ (return_reason): Moved to common-exceptions.h.
+ (enum return_reason): Likewise.
+ (RETURN_MASK): Likewise.
+ (typedef return_mask): Likewise.
+ (enum errors): Likewise.
+ (struct gdb_exception): Likewise.
+ (exceptions_state_mc_init): Likewise.
+ (exceptions_state_mc_action_iter): Likewise.
+ (exceptions_state_mc_action_iter_1): Likewise.
+ (TRY_CATCH): Likewise.
+ (throw_exception): Likewise.
+ (throw_verror): Likewise.
+ (throw_vquit): Likewise.
+ (throw_error): Likewise.
+ (throw_quit): Likewise.
+ * exceptions.c (enum catcher_state): Moved to common-exceptions.c.
+ (enum catcher_action): Likewise.
+ (struct catcher): Likewise.
+ (current_catcher): Likewise.
+ (catcher_list_size): Likewise.
+ (exceptions_state_mc_init): Likewise.
+ (catcher_pop): Likewise.
+ (exceptions_state_mc): Likewise.
+ (exceptions_state_mc_action_iter): Likewise.
+ (exceptions_state_mc_action_iter_1): Likewise.
+ (throw_exception): Likewise.
+ (exception_messages): Likewise.
+ (exception_messages_size): Likewise.
+ (throw_it): Likewise.
+ (throw_verror): Likewise.
+ (throw_vquit): Likewise.
+ (throw_error): Likewise.
+ (throw_quit): Likewise.
+ (prepare_to_throw_exception): New function.
+
+2014-08-29 Gary Benson <gbenson@redhat.com>
+
* common/gdb_setjmp.h: New file.
* Makefile.in (HFILES_NO_SRCDIR): Add common/gdb_setjmp.h.
* configure.ac: Move sigsetjmp check...
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c886c5d..fbcdfb3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -851,7 +851,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
target/waitstatus.c common/print-utils.c common/rsp-low.c \
- common/errors.c common/common-debug.c
+ common/errors.c common/common-debug.c common/common-exceptions.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -937,7 +937,8 @@ ctf.h nat/i386-cpuid.h nat/i386-gcc-cpuid.h target/resume.h \
target/wait.h target/waitstatus.h nat/linux-nat.h nat/linux-waitpid.h \
common/print-utils.h common/rsp-low.h nat/i386-dregs.h x86-linux-nat.h \
i386-linux-nat.h common/common-defs.h common/errors.h common/common-types.h \
-common/common-debug.h common/cleanups.h common/gdb_setjmp.h
+common/common-debug.h common/cleanups.h common/gdb_setjmp.h \
+common/common-exceptions.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1036,7 +1037,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
format.o registry.o btrace.o record-btrace.o waitstatus.o \
- print-utils.o rsp-low.o errors.o common-debug.o debug.o
+ print-utils.o rsp-low.o errors.o common-debug.o debug.o \
+ common-exceptions.o
TSOBS = inflow.o
@@ -2166,6 +2168,10 @@ cleanups.o: ${srcdir}/common/cleanups.c
$(COMPILE) $(srcdir)/common/cleanups.c
$(POSTCOMPILE)
+common-exceptions.o: ${srcdir}/common/common-exceptions.c
+ $(COMPILE) $(srcdir)/common/common-exceptions.c
+ $(POSTCOMPILE)
+
#
# gdb/target/ dependencies
#
diff --git a/gdb/common/common-exceptions.c b/gdb/common/common-exceptions.c
new file mode 100644
index 0000000..c382d86
--- /dev/null
+++ b/gdb/common/common-exceptions.c
@@ -0,0 +1,308 @@
+/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
+
+ Copyright (C) 1986-2014 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 "common-defs.h"
+#include "common-exceptions.h"
+#include "cleanups.h"
+
+/* Possible catcher states. */
+enum catcher_state {
+ /* Initial state, a new catcher has just been created. */
+ CATCHER_CREATED,
+ /* The catch code is running. */
+ CATCHER_RUNNING,
+ CATCHER_RUNNING_1,
+ /* The catch code threw an exception. */
+ CATCHER_ABORTING
+};
+
+/* Possible catcher actions. */
+enum catcher_action {
+ CATCH_ITER,
+ CATCH_ITER_1,
+ CATCH_THROWING
+};
+
+struct catcher
+{
+ enum catcher_state state;
+ /* Jump buffer pointing back at the exception handler. */
+ SIGJMP_BUF buf;
+ /* Status buffer belonging to the exception handler. */
+ volatile struct gdb_exception *exception;
+ /* Saved/current state. */
+ int mask;
+ struct cleanup *saved_cleanup_chain;
+ /* Back link. */
+ struct catcher *prev;
+};
+
+/* Where to go for throw_exception(). */
+static struct catcher *current_catcher;
+
+/* Return length of current_catcher list. */
+
+static int
+catcher_list_size (void)
+{
+ int size;
+ struct catcher *catcher;
+
+ for (size = 0, catcher = current_catcher;
+ catcher != NULL;
+ catcher = catcher->prev)
+ ++size;
+
+ return size;
+}
+
+SIGJMP_BUF *
+exceptions_state_mc_init (volatile struct gdb_exception *exception,
+ return_mask mask)
+{
+ struct catcher *new_catcher = XCNEW (struct catcher);
+
+ /* Start with no exception, save it's address. */
+ exception->reason = 0;
+ exception->error = GDB_NO_ERROR;
+ exception->message = NULL;
+ new_catcher->exception = exception;
+
+ new_catcher->mask = mask;
+
+ /* Prevent error/quit during FUNC from calling cleanups established
+ prior to here. */
+ new_catcher->saved_cleanup_chain = save_cleanups ();
+
+ /* 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;
+
+ /* Restore the cleanup chain, the error/quit messages, and the uiout
+ builder, to their original states. */
+
+ restore_cleanups (old_catcher->saved_cleanup_chain);
+
+ xfree (old_catcher);
+}
+
+/* Catcher state machine. Returns non-zero if the m/c should be run
+ again, zero if it should abort. */
+
+static int
+exceptions_state_mc (enum catcher_action action)
+{
+ switch (current_catcher->state)
+ {
+ case CATCHER_CREATED:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* Allow the code to run the catcher. */
+ current_catcher->state = CATCHER_RUNNING;
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, _("bad state"));
+ }
+ case CATCHER_RUNNING:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* No error/quit has occured. Just clean up. */
+ catcher_pop ();
+ return 0;
+ case CATCH_ITER_1:
+ current_catcher->state = CATCHER_RUNNING_1;
+ return 1;
+ case CATCH_THROWING:
+ current_catcher->state = CATCHER_ABORTING;
+ /* See also throw_exception. */
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, _("bad switch"));
+ }
+ case CATCHER_RUNNING_1:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* The did a "break" from the inner while loop. */
+ catcher_pop ();
+ return 0;
+ case CATCH_ITER_1:
+ current_catcher->state = CATCHER_RUNNING;
+ return 0;
+ case CATCH_THROWING:
+ current_catcher->state = CATCHER_ABORTING;
+ /* See also throw_exception. */
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, _("bad switch"));
+ }
+ case CATCHER_ABORTING:
+ switch (action)
+ {
+ case CATCH_ITER:
+ {
+ struct gdb_exception exception = *current_catcher->exception;
+
+ if (current_catcher->mask & RETURN_MASK (exception.reason))
+ {
+ /* Exit normally if this catcher can handle this
+ exception. The caller analyses the func return
+ values. */
+ catcher_pop ();
+ return 0;
+ }
+ /* The caller didn't request that the event be caught,
+ relay the event to the next containing
+ catch_errors(). */
+ catcher_pop ();
+ throw_exception (exception);
+ }
+ default:
+ internal_error (__FILE__, __LINE__, _("bad state"));
+ }
+ default:
+ internal_error (__FILE__, __LINE__, _("bad switch"));
+ }
+}
+
+int
+exceptions_state_mc_action_iter (void)
+{
+ return exceptions_state_mc (CATCH_ITER);
+}
+
+int
+exceptions_state_mc_action_iter_1 (void)
+{
+ return exceptions_state_mc (CATCH_ITER_1);
+}
+
+/* Return EXCEPTION to the nearest containing catch_errors(). */
+
+void
+throw_exception (struct gdb_exception exception)
+{
+ prepare_to_throw_exception ();
+
+ do_cleanups (all_cleanups ());
+
+ /* Jump to the containing catch_errors() call, communicating REASON
+ to that call via setjmp's return value. Note that REASON can't
+ be zero, by definition in defs.h. */
+ exceptions_state_mc (CATCH_THROWING);
+ *current_catcher->exception = exception;
+ SIGLONGJMP (current_catcher->buf, exception.reason);
+}
+
+/* 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 = catcher_list_size ();
+
+ 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 = (char **) xrealloc (exception_messages,
+ exception_messages_size
+ * sizeof (char *));
+ 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;
+
+ /* Throw the exception. */
+ throw_exception (e);
+}
+
+void
+throw_verror (enum errors error, const char *fmt, va_list ap)
+{
+ throw_it (RETURN_ERROR, error, fmt, ap);
+}
+
+void
+throw_vquit (const char *fmt, va_list ap)
+{
+ throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
+}
+
+void
+throw_error (enum errors error, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ throw_verror (error, fmt, args);
+ va_end (args);
+}
+
+void
+throw_quit (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ throw_vquit (fmt, args);
+ va_end (args);
+}
diff --git a/gdb/common/common-exceptions.h b/gdb/common/common-exceptions.h
new file mode 100644
index 0000000..5f750c3
--- /dev/null
+++ b/gdb/common/common-exceptions.h
@@ -0,0 +1,185 @@
+/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
+
+ Copyright (C) 1986-2014 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/>. */
+
+#ifndef COMMON_EXCEPTIONS_H
+#define COMMON_EXCEPTIONS_H
+
+#include "gdb_setjmp.h"
+
+/* Reasons for calling throw_exceptions(). NOTE: all reason values
+ must be less than zero. enum value 0 is reserved for internal use
+ as the return value from an initial setjmp(). The function
+ catch_exceptions() reserves values >= 0 as legal results from its
+ wrapped function. */
+
+enum return_reason
+ {
+ /* User interrupt. */
+ RETURN_QUIT = -2,
+ /* Any other error. */
+ RETURN_ERROR
+ };
+
+#define RETURN_MASK(reason) (1 << (int)(-reason))
+
+typedef enum
+{
+ RETURN_MASK_QUIT = RETURN_MASK (RETURN_QUIT),
+ RETURN_MASK_ERROR = RETURN_MASK (RETURN_ERROR),
+ RETURN_MASK_ALL = (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
+} return_mask;
+
+/* Describe all exceptions. */
+
+enum errors {
+ GDB_NO_ERROR,
+
+ /* Any generic error, the corresponding text is in
+ exception.message. */
+ GENERIC_ERROR,
+
+ /* Something requested was not found. */
+ NOT_FOUND_ERROR,
+
+ /* Thread library lacks support necessary for finding thread local
+ storage. */
+ TLS_NO_LIBRARY_SUPPORT_ERROR,
+
+ /* Load module not found while attempting to find thread local storage. */
+ TLS_LOAD_MODULE_NOT_FOUND_ERROR,
+
+ /* Thread local storage has not been allocated yet. */
+ TLS_NOT_ALLOCATED_YET_ERROR,
+
+ /* Something else went wrong while attempting to find thread local
+ storage. The ``struct gdb_exception'' message field provides
+ more detail. */
+ TLS_GENERIC_ERROR,
+
+ /* Problem parsing an XML document. */
+ XML_PARSE_ERROR,
+
+ /* Error accessing memory. */
+ MEMORY_ERROR,
+
+ /* Value not available. E.g., a register was not collected in a
+ traceframe. */
+ NOT_AVAILABLE_ERROR,
+
+ /* Value was optimized out. Note: if the value was a register, this
+ means the register was not saved in the frame. */
+ OPTIMIZED_OUT_ERROR,
+
+ /* DW_OP_GNU_entry_value resolving failed. */
+ NO_ENTRY_VALUE_ERROR,
+
+ /* Target throwing an error has been closed. Current command should be
+ aborted as the inferior state is no longer valid. */
+ TARGET_CLOSE_ERROR,
+
+ /* An undefined command was executed. */
+ UNDEFINED_COMMAND_ERROR,
+
+ /* Requested feature, method, mechanism, etc. is not supported. */
+ NOT_SUPPORTED_ERROR,
+
+ /* Add more errors here. */
+ NR_ERRORS
+};
+
+struct gdb_exception
+{
+ enum return_reason reason;
+ enum errors error;
+ const char *message;
+};
+
+/* Functions to drive the exceptions state machine. Though declared
+ here by necessity, these functions should be considered internal to
+ the exceptions subsystem and not used other than via the TRY_CATCH
+ macro defined below. */
+
+extern SIGJMP_BUF *exceptions_state_mc_init (volatile struct
+ gdb_exception *exception,
+ return_mask mask);
+extern int exceptions_state_mc_action_iter (void);
+extern int exceptions_state_mc_action_iter_1 (void);
+
+/* Macro to wrap up standard try/catch behavior.
+
+ The double loop lets us correctly handle code "break"ing out of the
+ try catch block. (It works as the "break" only exits the inner
+ "while" loop, the outer for loop detects this handling it
+ correctly.) Of course "return" and "goto" are not so lucky.
+
+ For instance:
+
+ *INDENT-OFF*
+
+ volatile struct gdb_exception e;
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ }
+ switch (e.reason)
+ {
+ case RETURN_ERROR: ...
+ }
+
+ */
+
+#define TRY_CATCH(EXCEPTION,MASK) \
+ { \
+ SIGJMP_BUF *buf = \
+ exceptions_state_mc_init (&(EXCEPTION), (MASK)); \
+ SIGSETJMP (*buf); \
+ } \
+ while (exceptions_state_mc_action_iter ()) \
+ while (exceptions_state_mc_action_iter_1 ())
+
+/* *INDENT-ON* */
+
+/* Hook to allow client-specific actions to be performed prior to
+ throwing an exception. This function must be provided by the
+ client, and will be called before any cleanups are run. */
+
+extern void prepare_to_throw_exception (void);
+
+/* Throw an exception (as described by "struct gdb_exception"). Will
+ execute a LONG JUMP to the inner most containing exception handler
+ established using catch_exceptions() (or similar).
+
+ Code normally throws an exception using error() et.al. For various
+ reaons, GDB also contains code that throws an exception directly.
+ For instance, the remote*.c targets contain CNTRL-C signal handlers
+ that propogate the QUIT event up the exception chain. ``This could
+ be a good thing or a dangerous thing.'' -- the Existential
+ Wombat. */
+
+extern void throw_exception (struct gdb_exception exception)
+ ATTRIBUTE_NORETURN;
+extern void throw_verror (enum errors, const char *fmt, va_list ap)
+ ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0);
+extern void throw_vquit (const char *fmt, va_list ap)
+ ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0);
+extern void throw_error (enum errors error, const char *fmt, ...)
+ ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
+extern void throw_quit (const char *fmt, ...)
+ ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
+
+#endif /* COMMON_EXCEPTIONS_H */
diff --git a/gdb/exceptions.c b/gdb/exceptions.c
index 48843ea..28b8dd1 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -29,207 +29,11 @@
const struct gdb_exception exception_none = { 0, GDB_NO_ERROR, NULL };
-/* Possible catcher states. */
-enum catcher_state {
- /* Initial state, a new catcher has just been created. */
- CATCHER_CREATED,
- /* The catch code is running. */
- CATCHER_RUNNING,
- CATCHER_RUNNING_1,
- /* The catch code threw an exception. */
- CATCHER_ABORTING
-};
-
-/* Possible catcher actions. */
-enum catcher_action {
- CATCH_ITER,
- CATCH_ITER_1,
- CATCH_THROWING
-};
-
-struct catcher
-{
- enum catcher_state state;
- /* Jump buffer pointing back at the exception handler. */
- SIGJMP_BUF buf;
- /* Status buffer belonging to the exception handler. */
- volatile struct gdb_exception *exception;
- /* Saved/current state. */
- int mask;
- struct cleanup *saved_cleanup_chain;
- /* Back link. */
- struct catcher *prev;
-};
-
-/* Where to go for throw_exception(). */
-static struct catcher *current_catcher;
-
-/* Return length of current_catcher list. */
-
-static int
-catcher_list_size (void)
-{
- int size;
- struct catcher *catcher;
-
- for (size = 0, catcher = current_catcher;
- catcher != NULL;
- catcher = catcher->prev)
- ++size;
-
- return size;
-}
-
-SIGJMP_BUF *
-exceptions_state_mc_init (volatile struct gdb_exception *exception,
- return_mask mask)
-{
- struct catcher *new_catcher = XCNEW (struct catcher);
-
- /* Start with no exception, save it's address. */
- exception->reason = 0;
- exception->error = GDB_NO_ERROR;
- exception->message = NULL;
- new_catcher->exception = exception;
-
- new_catcher->mask = mask;
-
- /* Prevent error/quit during FUNC from calling cleanups established
- prior to here. */
- new_catcher->saved_cleanup_chain = save_cleanups ();
-
- /* 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;
-
- /* Restore the cleanup chain, the error/quit messages, and the uiout
- builder, to their original states. */
-
- restore_cleanups (old_catcher->saved_cleanup_chain);
-
- xfree (old_catcher);
-}
-
-/* Catcher state machine. Returns non-zero if the m/c should be run
- again, zero if it should abort. */
-
-static int
-exceptions_state_mc (enum catcher_action action)
-{
- switch (current_catcher->state)
- {
- case CATCHER_CREATED:
- switch (action)
- {
- case CATCH_ITER:
- /* Allow the code to run the catcher. */
- current_catcher->state = CATCHER_RUNNING;
- return 1;
- default:
- internal_error (__FILE__, __LINE__, _("bad state"));
- }
- case CATCHER_RUNNING:
- switch (action)
- {
- case CATCH_ITER:
- /* No error/quit has occured. Just clean up. */
- catcher_pop ();
- return 0;
- case CATCH_ITER_1:
- current_catcher->state = CATCHER_RUNNING_1;
- return 1;
- case CATCH_THROWING:
- current_catcher->state = CATCHER_ABORTING;
- /* See also throw_exception. */
- return 1;
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
- }
- case CATCHER_RUNNING_1:
- switch (action)
- {
- case CATCH_ITER:
- /* The did a "break" from the inner while loop. */
- catcher_pop ();
- return 0;
- case CATCH_ITER_1:
- current_catcher->state = CATCHER_RUNNING;
- return 0;
- case CATCH_THROWING:
- current_catcher->state = CATCHER_ABORTING;
- /* See also throw_exception. */
- return 1;
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
- }
- case CATCHER_ABORTING:
- switch (action)
- {
- case CATCH_ITER:
- {
- struct gdb_exception exception = *current_catcher->exception;
-
- if (current_catcher->mask & RETURN_MASK (exception.reason))
- {
- /* Exit normally if this catcher can handle this
- exception. The caller analyses the func return
- values. */
- catcher_pop ();
- return 0;
- }
- /* The caller didn't request that the event be caught,
- relay the event to the next containing
- catch_errors(). */
- catcher_pop ();
- throw_exception (exception);
- }
- default:
- internal_error (__FILE__, __LINE__, _("bad state"));
- }
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
- }
-}
-
-int
-exceptions_state_mc_action_iter (void)
-{
- return exceptions_state_mc (CATCH_ITER);
-}
-
-int
-exceptions_state_mc_action_iter_1 (void)
-{
- return exceptions_state_mc (CATCH_ITER_1);
-}
-
-/* Return EXCEPTION to the nearest containing catch_errors(). */
-
void
-throw_exception (struct gdb_exception exception)
+prepare_to_throw_exception (void)
{
clear_quit_flag ();
immediate_quit = 0;
-
- do_cleanups (all_cleanups ());
-
- /* Jump to the containing catch_errors() call, communicating REASON
- to that call via setjmp's return value. Note that REASON can't
- be zero, by definition in defs.h. */
- exceptions_state_mc (CATCH_THROWING);
- *current_catcher->exception = exception;
- SIGLONGJMP (current_catcher->buf, exception.reason);
}
static void
@@ -332,90 +136,6 @@ exception_fprintf (struct ui_file *file, struct gdb_exception e,
}
}
-/* 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 = catcher_list_size ();
-
- 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 = (char **) xrealloc (exception_messages,
- exception_messages_size
- * sizeof (char *));
- 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;
-
- /* Throw the exception. */
- throw_exception (e);
-}
-
-void
-throw_verror (enum errors error, const char *fmt, va_list ap)
-{
- throw_it (RETURN_ERROR, error, fmt, ap);
-}
-
-void
-throw_vquit (const char *fmt, va_list ap)
-{
- throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
-}
-
-void
-throw_error (enum errors error, const char *fmt, ...)
-{
- va_list args;
-
- va_start (args, fmt);
- throw_verror (error, fmt, args);
- va_end (args);
-}
-
-void
-throw_quit (const char *fmt, ...)
-{
- va_list args;
-
- va_start (args, fmt);
- throw_vquit (fmt, args);
- va_end (args);
-}
-
/* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception
handler. If an exception (enum return_reason) is thrown using
throw_exception() than all cleanups installed since
diff --git a/gdb/exceptions.h b/gdb/exceptions.h
index e3ff672..00d2b61 100644
--- a/gdb/exceptions.h
+++ b/gdb/exceptions.h
@@ -20,142 +20,12 @@
#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H
+#include "common-exceptions.h"
#include "ui-out.h"
-#include "gdb_setjmp.h"
-
-/* Reasons for calling throw_exceptions(). NOTE: all reason values
- must be less than zero. enum value 0 is reserved for internal use
- as the return value from an initial setjmp(). The function
- catch_exceptions() reserves values >= 0 as legal results from its
- wrapped function. */
-
-enum return_reason
- {
- /* User interrupt. */
- RETURN_QUIT = -2,
- /* Any other error. */
- RETURN_ERROR
- };
-
-#define RETURN_MASK(reason) (1 << (int)(-reason))
-
-typedef enum
-{
- RETURN_MASK_QUIT = RETURN_MASK (RETURN_QUIT),
- RETURN_MASK_ERROR = RETURN_MASK (RETURN_ERROR),
- RETURN_MASK_ALL = (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
-} return_mask;
-
-/* Describe all exceptions. */
-
-enum errors {
- GDB_NO_ERROR,
-
- /* Any generic error, the corresponding text is in
- exception.message. */
- GENERIC_ERROR,
-
- /* Something requested was not found. */
- NOT_FOUND_ERROR,
-
- /* Thread library lacks support necessary for finding thread local
- storage. */
- TLS_NO_LIBRARY_SUPPORT_ERROR,
-
- /* Load module not found while attempting to find thread local storage. */
- TLS_LOAD_MODULE_NOT_FOUND_ERROR,
-
- /* Thread local storage has not been allocated yet. */
- TLS_NOT_ALLOCATED_YET_ERROR,
-
- /* Something else went wrong while attempting to find thread local
- storage. The ``struct gdb_exception'' message field provides
- more detail. */
- TLS_GENERIC_ERROR,
-
- /* Problem parsing an XML document. */
- XML_PARSE_ERROR,
-
- /* Error accessing memory. */
- MEMORY_ERROR,
-
- /* Value not available. E.g., a register was not collected in a
- traceframe. */
- NOT_AVAILABLE_ERROR,
-
- /* Value was optimized out. Note: if the value was a register, this
- means the register was not saved in the frame. */
- OPTIMIZED_OUT_ERROR,
-
- /* DW_OP_GNU_entry_value resolving failed. */
- NO_ENTRY_VALUE_ERROR,
-
- /* Target throwing an error has been closed. Current command should be
- aborted as the inferior state is no longer valid. */
- TARGET_CLOSE_ERROR,
-
- /* An undefined command was executed. */
- UNDEFINED_COMMAND_ERROR,
-
- /* Requested feature, method, mechanism, etc. is not supported. */
- NOT_SUPPORTED_ERROR,
-
- /* Add more errors here. */
- NR_ERRORS
-};
-
-struct gdb_exception
-{
- enum return_reason reason;
- enum errors error;
- const char *message;
-};
/* A pre-defined non-exception. */
extern const struct gdb_exception exception_none;
-/* Functions to drive the exceptions state m/c (internal to
- exceptions). */
-SIGJMP_BUF *exceptions_state_mc_init (volatile struct
- gdb_exception *exception,
- return_mask mask);
-int exceptions_state_mc_action_iter (void);
-int exceptions_state_mc_action_iter_1 (void);
-
-/* Macro to wrap up standard try/catch behavior.
-
- The double loop lets us correctly handle code "break"ing out of the
- try catch block. (It works as the "break" only exits the inner
- "while" loop, the outer for loop detects this handling it
- correctly.) Of course "return" and "goto" are not so lucky.
-
- For instance:
-
- *INDENT-OFF*
-
- volatile struct gdb_exception e;
- TRY_CATCH (e, RETURN_MASK_ERROR)
- {
- }
- switch (e.reason)
- {
- case RETURN_ERROR: ...
- }
-
- */
-
-#define TRY_CATCH(EXCEPTION,MASK) \
- { \
- SIGJMP_BUF *buf = \
- exceptions_state_mc_init (&(EXCEPTION), (MASK)); \
- SIGSETJMP (*buf); \
- } \
- while (exceptions_state_mc_action_iter ()) \
- while (exceptions_state_mc_action_iter_1 ())
-
-/* *INDENT-ON* */
-
-
/* If E is an exception, print it's error message on the specified
stream. For _fprintf, prefix the message with PREFIX... */
extern void exception_print (struct ui_file *file, struct gdb_exception e);
@@ -163,28 +33,6 @@ extern void exception_fprintf (struct ui_file *file, struct gdb_exception e,
const char *prefix,
...) ATTRIBUTE_PRINTF (3, 4);
-/* Throw an exception (as described by "struct gdb_exception"). Will
- execute a LONG JUMP to the inner most containing exception handler
- established using catch_exceptions() (or similar).
-
- Code normally throws an exception using error() et.al. For various
- reaons, GDB also contains code that throws an exception directly.
- For instance, the remote*.c targets contain CNTRL-C signal handlers
- that propogate the QUIT event up the exception chain. ``This could
- be a good thing or a dangerous thing.'' -- the Existential
- Wombat. */
-
-extern void throw_exception (struct gdb_exception exception)
- ATTRIBUTE_NORETURN;
-extern void throw_verror (enum errors, const char *fmt, va_list ap)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0);
-extern void throw_vquit (const char *fmt, va_list ap)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0);
-extern void throw_error (enum errors error, const char *fmt, ...)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
-extern void throw_quit (const char *fmt, ...)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
-
/* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception
handler. If an exception (enum return_reason) is thrown using
throw_exception() than all cleanups installed since
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 453854e..89cafa6 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,12 @@
2014-08-29 Gary Benson <gbenson@redhat.com>
+ * Makefile.in (SFILES): Add common/common-exceptions.c.
+ (OBS): Add common-exceptions.o.
+ (common-exceptions.o): New rule.
+ * utils.c (prepare_to_throw_exception): New function.
+
+2014-08-29 Gary Benson <gbenson@redhat.com>
+
* config.in: Regenerate.
* configure: Likewise.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index f130082..21ac6f2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -170,7 +170,8 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
$(srcdir)/common/filestuff.c $(srcdir)/target/waitstatus.c \
$(srcdir)/nat/mips-linux-watch.c $(srcdir)/common/print-utils.c \
$(srcdir)/common/rsp-low.c $(srcdir)/common/errors.c \
- $(srcdir)/common/common-debug.c $(srcdir)/common/cleanups.c
+ $(srcdir)/common/common-debug.c $(srcdir)/common/cleanups.c \
+ $(srcdir)/common/common-exceptions.c
DEPFILES = @GDBSERVER_DEPFILES@
@@ -184,6 +185,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
+ common-exceptions.o \
$(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
GDBREPLAY_OBS = gdbreplay.o version.o
GDBSERVER_LIBS = @GDBSERVER_LIBS@
@@ -547,6 +549,9 @@ common-debug.o: ../common/common-debug.c
cleanups.o: ../common/cleanups.c
$(COMPILE) $<
$(POSTCOMPILE)
+common-exceptions.o: ../common/common-exceptions.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
waitstatus.o: ../target/waitstatus.c
$(COMPILE) $<
$(POSTCOMPILE)
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 244e114..e310b9e 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -141,3 +141,11 @@ pfildes (gdb_fildes_t fd)
return plongest (fd);
#endif
}
+
+/* See common/common-exceptions.h. */
+
+void
+prepare_to_throw_exception (void)
+{
+ /* No client-specific actions required. */
+}