Introduce common/common-exceptions.[ch]
authorGary Benson <gbenson@redhat.com>
Thu, 7 Aug 2014 15:29:19 +0000 (16:29 +0100)
committerGary Benson <gbenson@redhat.com>
Fri, 29 Aug 2014 09:53:37 +0000 (10:53 +0100)
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.

gdb/ChangeLog
gdb/Makefile.in
gdb/common/common-exceptions.c [new file with mode: 0644]
gdb/common/common-exceptions.h [new file with mode: 0644]
gdb/exceptions.c
gdb/exceptions.h
gdb/gdbserver/ChangeLog
gdb/gdbserver/Makefile.in
gdb/gdbserver/utils.c

index fbe8e87a41f49182665834aeb056b9b317b34a25..07f0c5e74a892048f4a0b6cbe8f123ec706d425a 100644 (file)
@@ -1,3 +1,48 @@
+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.
index c886c5d0ba857989ecb5180bf470bf444a37aa11..fbcdfb3e3c0376f8242cb19431d48908921d2f5f 100644 (file)
@@ -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 (file)
index 0000000..c382d86
--- /dev/null
@@ -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 (file)
index 0000000..5f750c3
--- /dev/null
@@ -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 */
index 48843eae753a76c8f7e1111d45e5004b22d2e7ee..28b8dd1bce65e6181e93feca5005b4b543227cd4 100644 (file)
 
 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
index e3ff672f264e4ff030fd4de4ec3eaede2fdc523f..00d2b6126c566ddec89eaa09a0e60ec095a1a4ec 100644 (file)
 #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
index 453854ef19aee7643c48868ae42da7a3aa89869e..89cafa69a250c6079fc4f3c16b5372b267758b45 100644 (file)
@@ -1,3 +1,10 @@
+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.
index f1300826933dae7d54063cf742b2b54e4ca8cd66..21ac6f2a51e91d093d1b352b97c119ad9e9fd117 100644 (file)
@@ -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)
index 244e114c70fbf9e0afc392b83fd665f8e16cd243..e310b9e1405fe7f5f800ab8f3fa6523a2f4734af 100644 (file)
@@ -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.  */
+}