* gdb.threads/gcore-thread.exp: Use gdb_gcore_cmd.
[deliverable/binutils-gdb.git] / gdb / exceptions.c
index f917c94ea16dd9b49ca2e737f03c6ee86fd38c99..b7cf9a2cd8fba6b8921b72881f753ce43a154f33 100644 (file)
@@ -1,8 +1,6 @@
 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
 
-   Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright (C) 1986, 1988-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -60,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;
@@ -69,9 +66,24 @@ 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);
@@ -84,12 +96,8 @@ exceptions_state_mc_init (struct ui_out *func_uiout,
 
   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.  */
@@ -104,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);
 }
 
@@ -174,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
@@ -184,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);
          }
@@ -210,39 +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)
 {
-  struct thread_info *tp = NULL;
-
-  quit_flag = 0;
+  clear_quit_flag ();
   immediate_quit = 0;
 
-  if (!ptid_equal (inferior_ptid, null_ptid))
-    tp = find_thread_pid (inferior_ptid);
-
-  /* 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).  */
-  if (tp != NULL)
-    bpstat_clear_actions (tp->stop_bpstat);    /* Clear queued breakpoint commands */
-
-  disable_current_display ();
-  do_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;
@@ -299,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');
@@ -356,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 ();
 
@@ -374,80 +371,103 @@ print_any_exception (struct ui_file *file, const char *prefix,
     }
 }
 
-NORETURN static void ATTR_NORETURN ATTR_FORMAT (printf, 3, 0)
+/* 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);
 
-  /* Save the message.  Create the new message before deleting the
-     old, the new message may include the old message text.  */
+  /* 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, 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,
@@ -458,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,
@@ -481,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);
@@ -505,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;
@@ -526,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.030211 seconds and 4 git commands to generate.