[4/5] Introduce common/common-exceptions.[ch]

Message ID 1408351618-21013-5-git-send-email-gbenson@redhat.com
State Committed
Headers

Commit Message

Gary Benson Aug. 18, 2014, 8:46 a.m. UTC
  This commit moves the exception throwing and catching code
into gdb/common/.  All exception printing code remains in
gdb/exceptions.[ch].

gdb/
2014-08-18  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.

gdb/gdbserver/
2014-08-18  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.
---
 gdb/ChangeLog                  |   45 ++++++
 gdb/Makefile.in                |   11 +-
 gdb/common/common-exceptions.c |  308 ++++++++++++++++++++++++++++++++++++++++
 gdb/common/common-exceptions.h |  185 ++++++++++++++++++++++++
 gdb/exceptions.c               |  282 +------------------------------------
 gdb/exceptions.h               |  154 +--------------------
 gdb/gdbserver/ChangeLog        |    7 +
 gdb/gdbserver/Makefile.in      |    7 +-
 gdb/gdbserver/utils.c          |    8 +
 9 files changed, 569 insertions(+), 438 deletions(-)
 create mode 100644 gdb/common/common-exceptions.c
 create mode 100644 gdb/common/common-exceptions.h
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 951a738..3298825 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
 
@@ -939,7 +939,7 @@  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 target/target.h target/symbol.h common/common-regcache.h
 common/common-debug.h target/target.h target/symbol.h common/common-regcache.h \
-common/cleanups.h common/gdb_setjmp.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.
 
@@ -1038,7 +1038,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
 
@@ -2160,6 +2161,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 99a147c..5533758 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
@@ -329,90 +133,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/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 3ec4add..6283877 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -160,3 +160,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.  */
+}