* gdb.threads/gcore-thread.exp: Use gdb_gcore_cmd.
[deliverable/binutils-gdb.git] / gdb / exceptions.c
index 37b8a9e1872e71eeb58c229d8d259a8a3b746336..b7cf9a2cd8fba6b8921b72881f753ce43a154f33 100644 (file)
@@ -1,14 +1,12 @@
 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
 
-   Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
-   1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
-   Software Foundation, Inc.
+   Copyright (C) 1986, 1988-2012 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 2 of the License, or
+   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,
@@ -17,9 +15,7 @@
    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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "exceptions.h"
@@ -31,8 +27,9 @@
 #include "gdb_assert.h"
 #include "gdb_string.h"
 #include "serial.h"
+#include "gdbthread.h"
 
-const struct gdb_exception exception_none = { 0, NO_ERROR, NULL };
+const struct gdb_exception exception_none = { 0, GDB_NO_ERROR, NULL };
 
 /* Possible catcher states.  */
 enum catcher_state {
@@ -61,7 +58,6 @@ struct catcher
   volatile struct gdb_exception *exception;
   /* Saved/current state.  */
   int mask;
-  struct ui_out *saved_uiout;
   struct cleanup *saved_cleanup_chain;
   /* Back link.  */
   struct catcher *prev;
@@ -70,27 +66,38 @@ struct catcher
 /* 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;
+}
+
 EXCEPTIONS_SIGJMP_BUF *
-exceptions_state_mc_init (struct ui_out *func_uiout,
-                         volatile struct gdb_exception *exception,
+exceptions_state_mc_init (volatile struct gdb_exception *exception,
                          return_mask mask)
 {
   struct catcher *new_catcher = XZALLOC (struct catcher);
 
   /* Start with no exception, save it's address.  */
   exception->reason = 0;
-  exception->error = NO_ERROR;
+  exception->error = GDB_NO_ERROR;
   exception->message = NULL;
   new_catcher->exception = exception;
 
   new_catcher->mask = mask;
 
-  /* Override the global ``struct ui_out'' builder.  */
-  new_catcher->saved_uiout = uiout;
-  uiout = func_uiout;
-
   /* Prevent error/quit during FUNC from calling cleanups established
-     prior to here. */
+     prior to here.  */
   new_catcher->saved_cleanup_chain = save_cleanups ();
 
   /* Push this new catcher on the top.  */
@@ -105,15 +112,14 @@ 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. */
+     builder, to their original states.  */
 
   restore_cleanups (old_catcher->saved_cleanup_chain);
 
-  uiout = old_catcher->saved_uiout;
-
   xfree (old_catcher);
 }
 
@@ -175,6 +181,7 @@ exceptions_state_mc (enum catcher_action 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
@@ -185,7 +192,7 @@ exceptions_state_mc (enum catcher_action action)
              }
            /* The caller didn't request that the event be caught,
               relay the event to the next containing
-              catch_errors(). */
+              catch_errors().  */
            catcher_pop ();
            throw_exception (exception);
          }
@@ -211,37 +218,27 @@ exceptions_state_mc_action_iter_1 (void)
 
 /* Return EXCEPTION to the nearest containing catch_errors().  */
 
-NORETURN void
+void
 throw_exception (struct gdb_exception exception)
 {
-  quit_flag = 0;
+  clear_quit_flag ();
   immediate_quit = 0;
 
-  /* Perhaps it would be cleaner to do this via the cleanup chain (not sure
-     I can think of a reason why that is vital, though).  */
-  bpstat_clear_actions (stop_bpstat);  /* Clear queued breakpoint commands */
-
-  disable_current_display ();
-  do_cleanups (ALL_CLEANUPS);
-  if (target_can_async_p () && !target_executing)
-    do_exec_cleanups (ALL_CLEANUPS);
-  if (sync_execution)
-    do_exec_error_cleanups (ALL_CLEANUPS);
+  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. */
+     be zero, by definition in defs.h.  */
   exceptions_state_mc (CATCH_THROWING);
   *current_catcher->exception = exception;
   EXCEPTIONS_SIGLONGJMP (current_catcher->buf, exception.reason);
 }
 
-static char *last_message;
-
-NORETURN void
+void
 deprecated_throw_reason (enum return_reason reason)
 {
   struct gdb_exception exception;
+
   memset (&exception, 0, sizeof exception);
 
   exception.reason = reason;
@@ -282,8 +279,11 @@ print_flush (void)
 
   /* 3.  The system-level buffer.  */
   gdb_stdout_serial = serial_fdopen (1);
-  serial_drain_output (gdb_stdout_serial);
-  serial_un_fdopen (gdb_stdout_serial);
+  if (gdb_stdout_serial)
+    {
+      serial_drain_output (gdb_stdout_serial);
+      serial_un_fdopen (gdb_stdout_serial);
+    }
 
   annotate_error_begin ();
 }
@@ -295,6 +295,7 @@ print_exception (struct ui_file *file, struct gdb_exception e)
      as that way the MI's behavior is preserved.  */
   const char *start;
   const char *end;
+
   for (start = e.message; start != NULL; start = end)
     {
       end = strchr (start, '\n');
@@ -352,14 +353,14 @@ exception_fprintf (struct ui_file *file, struct gdb_exception e,
     }
 }
 
-void
+static void
 print_any_exception (struct ui_file *file, const char *prefix,
                     struct gdb_exception e)
 {
   if (e.reason < 0 && e.message != NULL)
     {
       target_terminal_ours ();
-      wrap_here ("");          /* Force out any buffered output */
+      wrap_here ("");          /* Force out any buffered output */
       gdb_flush (gdb_stdout);
       annotate_error_begin ();
 
@@ -370,83 +371,103 @@ print_any_exception (struct ui_file *file, const char *prefix,
     }
 }
 
-NORETURN static void
-throw_it (enum return_reason reason, enum errors error, const char *fmt,
-         va_list ap) ATTR_NORETURN;
-NORETURN static void
+/* 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 ();
 
-  /* Save the message.  Create the new message before deleting the
-     old, the new message may include the old message text.  */
+  gdb_assert (depth > 0);
+
+  /* Note: The new message may use an old message's text.  */
   new_message = xstrvprintf (fmt, ap);
-  xfree (last_message);
-  last_message = new_message;
+
+  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 = last_message;
+  e.message = new_message;
 
   /* Throw the exception.  */
   throw_exception (e);
 }
 
-NORETURN void
+void
 throw_verror (enum errors error, const char *fmt, va_list ap)
 {
   throw_it (RETURN_ERROR, error, fmt, ap);
 }
 
-NORETURN void
+void
 throw_vfatal (const char *fmt, va_list ap)
 {
-  throw_it (RETURN_QUIT, NO_ERROR, fmt, ap);
+  throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
 }
 
-NORETURN void
+void
 throw_error (enum errors error, const char *fmt, ...)
 {
   va_list args;
+
   va_start (args, fmt);
   throw_it (RETURN_ERROR, error, fmt, args);
   va_end (args);
 }
 
-/* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any
-   errors.  Set FUNC_CAUGHT to an ``enum return_reason'' if the
-   function is aborted (using throw_exception() or zero if the
-   function returns normally.  Set FUNC_VAL to the value returned by
-   the function or 0 if the function was aborted.
+/* 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
+   catch_exceptions() was entered are invoked, the (-ve) exception
+   value is then returned by catch_exceptions.  If FUNC() returns
+   normally (with a positive or zero return value) then that value is
+   returned by catch_exceptions().  It is an internal_error() for
+   FUNC() to return a negative value.
+
+   See exceptions.h for further usage details.
 
    Must not be called with immediate_quit in effect (bad things might
    happen, say we got a signal in the middle of a memcpy to quit_return).
    This is an OK restriction; with very few exceptions immediate_quit can
-   be replaced by judicious use of QUIT.
-
-   MASK specifies what to catch; it is normally set to
-   RETURN_MASK_ALL, if for no other reason than that the code which
-   calls catch_errors might not be set up to deal with a quit which
-   isn't caught.  But if the code can deal with it, it generally
-   should be RETURN_MASK_ERROR, unless for some reason it is more
-   useful to abort only the portion of the operation inside the
-   catch_errors.  Note that quit should return to the command line
-   fairly quickly, even if some further processing is being done.  */
+   be replaced by judicious use of QUIT.  */
 
 /* MAYBE: cagney/1999-11-05: catch_errors() in conjunction with
-   error() et.al. could maintain a set of flags that indicate the the
+   error() et al. could maintain a set of flags that indicate the
    current state of each of the longjmp buffers.  This would give the
    longjmp code the chance to detect a longjmp botch (before it gets
    to longjmperror()).  Prior to 1999-11-05 this wasn't possible as
    code also randomly used a SET_TOP_LEVEL macro that directly
-   initialize the longjmp buffers. */
-
-/* MAYBE: cagney/1999-11-05: Should the catch_errors and cleanups code
-   be consolidated into a single file instead of being distributed
-   between utils.c and top.c? */
+   initialized the longjmp buffers.  */
 
 int
 catch_exceptions (struct ui_out *uiout,
@@ -457,22 +478,8 @@ catch_exceptions (struct ui_out *uiout,
   return catch_exceptions_with_msg (uiout, func, func_args, NULL, mask);
 }
 
-struct gdb_exception
-catch_exception (struct ui_out *uiout,
-                catch_exception_ftype *func,
-                void *func_args,
-                return_mask mask)
-{
-  volatile struct gdb_exception exception;
-  TRY_CATCH (exception, mask)
-    {
-      (*func) (uiout, func_args);
-    }
-  return exception;
-}
-
 int
-catch_exceptions_with_msg (struct ui_out *uiout,
+catch_exceptions_with_msg (struct ui_out *func_uiout,
                           catch_exceptions_ftype *func,
                           void *func_args,
                           char **gdberrmsg,
@@ -480,10 +487,27 @@ catch_exceptions_with_msg (struct ui_out *uiout,
 {
   volatile struct gdb_exception exception;
   volatile int val = 0;
-  TRY_CATCH (exception, mask)
+  struct ui_out *saved_uiout;
+
+  /* Save and override the global ``struct ui_out'' builder.  */
+  saved_uiout = current_uiout;
+  current_uiout = func_uiout;
+
+  TRY_CATCH (exception, RETURN_MASK_ALL)
     {
-      val = (*func) (uiout, func_args);
+      val = (*func) (current_uiout, func_args);
     }
+
+  /* Restore the global builder.  */
+  current_uiout = saved_uiout;
+
+  if (exception.reason < 0 && (mask & RETURN_MASK (exception.reason)) == 0)
+    {
+      /* The caller didn't request that the event be caught.
+        Rethrow.  */
+      throw_exception (exception);
+    }
+
   print_any_exception (gdb_stderr, NULL, exception);
   gdb_assert (val >= 0);
   gdb_assert (exception.reason <= 0);
@@ -504,16 +528,34 @@ catch_exceptions_with_msg (struct ui_out *uiout,
   return val;
 }
 
+/* This function is superseded by catch_exceptions().  */
+
 int
 catch_errors (catch_errors_ftype *func, void *func_args, char *errstring,
              return_mask mask)
 {
   volatile int val = 0;
   volatile struct gdb_exception exception;
-  TRY_CATCH (exception, mask)
+  struct ui_out *saved_uiout;
+
+  /* Save the global ``struct ui_out'' builder.  */
+  saved_uiout = current_uiout;
+
+  TRY_CATCH (exception, RETURN_MASK_ALL)
     {
       val = func (func_args);
     }
+
+  /* Restore the global builder.  */
+  current_uiout = saved_uiout;
+
+  if (exception.reason < 0 && (mask & RETURN_MASK (exception.reason)) == 0)
+    {
+      /* The caller didn't request that the event be caught.
+        Rethrow.  */
+      throw_exception (exception);
+    }
+
   print_any_exception (gdb_stderr, errstring, exception);
   if (exception.reason != 0)
     return 0;
@@ -525,6 +567,7 @@ catch_command_errors (catch_command_errors_ftype * command,
                      char *arg, int from_tty, return_mask mask)
 {
   volatile struct gdb_exception e;
+
   TRY_CATCH (e, mask)
     {
       command (arg, from_tty);
This page took 0.029213 seconds and 4 git commands to generate.