gdb/common/common-exceptions.c - gdb

Global variables defined

Data types defined

Functions defined

Source code

  1. /* Exception (throw catch) mechanism, for GDB, the GNU debugger.

  2.    Copyright (C) 1986-2015 Free Software Foundation, Inc.

  3.    This file is part of GDB.

  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 3 of the License, or
  7.    (at your option) any later version.

  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.

  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  14. #include "common-defs.h"
  15. #include "common-exceptions.h"

  16. /* Possible catcher states.  */
  17. enum catcher_state {
  18.   /* Initial state, a new catcher has just been created.  */
  19.   CATCHER_CREATED,
  20.   /* The catch code is running.  */
  21.   CATCHER_RUNNING,
  22.   CATCHER_RUNNING_1,
  23.   /* The catch code threw an exception.  */
  24.   CATCHER_ABORTING
  25. };

  26. /* Possible catcher actions.  */
  27. enum catcher_action {
  28.   CATCH_ITER,
  29.   CATCH_ITER_1,
  30.   CATCH_THROWING
  31. };

  32. struct catcher
  33. {
  34.   enum catcher_state state;
  35.   /* Jump buffer pointing back at the exception handler.  */
  36.   SIGJMP_BUF buf;
  37.   /* Status buffer belonging to the exception handler.  */
  38.   volatile struct gdb_exception *exception;
  39.   /* Saved/current state.  */
  40.   int mask;
  41.   struct cleanup *saved_cleanup_chain;
  42.   /* Back link.  */
  43.   struct catcher *prev;
  44. };

  45. /* Where to go for throw_exception().  */
  46. static struct catcher *current_catcher;

  47. /* Return length of current_catcher list.  */

  48. static int
  49. catcher_list_size (void)
  50. {
  51.   int size;
  52.   struct catcher *catcher;

  53.   for (size = 0, catcher = current_catcher;
  54.        catcher != NULL;
  55.        catcher = catcher->prev)
  56.     ++size;

  57.   return size;
  58. }

  59. SIGJMP_BUF *
  60. exceptions_state_mc_init (volatile struct gdb_exception *exception,
  61.                           return_mask mask)
  62. {
  63.   struct catcher *new_catcher = XCNEW (struct catcher);

  64.   /* Start with no exception, save it's address.  */
  65.   exception->reason = 0;
  66.   exception->error = GDB_NO_ERROR;
  67.   exception->message = NULL;
  68.   new_catcher->exception = exception;

  69.   new_catcher->mask = mask;

  70.   /* Prevent error/quit during FUNC from calling cleanups established
  71.      prior to here.  */
  72.   new_catcher->saved_cleanup_chain = save_cleanups ();

  73.   /* Push this new catcher on the top.  */
  74.   new_catcher->prev = current_catcher;
  75.   current_catcher = new_catcher;
  76.   new_catcher->state = CATCHER_CREATED;

  77.   return &new_catcher->buf;
  78. }

  79. static void
  80. catcher_pop (void)
  81. {
  82.   struct catcher *old_catcher = current_catcher;

  83.   current_catcher = old_catcher->prev;

  84.   /* Restore the cleanup chain, the error/quit messages, and the uiout
  85.      builder, to their original states.  */

  86.   restore_cleanups (old_catcher->saved_cleanup_chain);

  87.   xfree (old_catcher);
  88. }

  89. /* Catcher state machine.  Returns non-zero if the m/c should be run
  90.    again, zero if it should abort.  */

  91. static int
  92. exceptions_state_mc (enum catcher_action action)
  93. {
  94.   switch (current_catcher->state)
  95.     {
  96.     case CATCHER_CREATED:
  97.       switch (action)
  98.         {
  99.         case CATCH_ITER:
  100.           /* Allow the code to run the catcher.  */
  101.           current_catcher->state = CATCHER_RUNNING;
  102.           return 1;
  103.         default:
  104.           internal_error (__FILE__, __LINE__, _("bad state"));
  105.         }
  106.     case CATCHER_RUNNING:
  107.       switch (action)
  108.         {
  109.         case CATCH_ITER:
  110.           /* No error/quit has occured.  Just clean up.  */
  111.           catcher_pop ();
  112.           return 0;
  113.         case CATCH_ITER_1:
  114.           current_catcher->state = CATCHER_RUNNING_1;
  115.           return 1;
  116.         case CATCH_THROWING:
  117.           current_catcher->state = CATCHER_ABORTING;
  118.           /* See also throw_exception.  */
  119.           return 1;
  120.         default:
  121.           internal_error (__FILE__, __LINE__, _("bad switch"));
  122.         }
  123.     case CATCHER_RUNNING_1:
  124.       switch (action)
  125.         {
  126.         case CATCH_ITER:
  127.           /* The did a "break" from the inner while loop.  */
  128.           catcher_pop ();
  129.           return 0;
  130.         case CATCH_ITER_1:
  131.           current_catcher->state = CATCHER_RUNNING;
  132.           return 0;
  133.         case CATCH_THROWING:
  134.           current_catcher->state = CATCHER_ABORTING;
  135.           /* See also throw_exception.  */
  136.           return 1;
  137.         default:
  138.           internal_error (__FILE__, __LINE__, _("bad switch"));
  139.         }
  140.     case CATCHER_ABORTING:
  141.       switch (action)
  142.         {
  143.         case CATCH_ITER:
  144.           {
  145.             struct gdb_exception exception = *current_catcher->exception;

  146.             if (current_catcher->mask & RETURN_MASK (exception.reason))
  147.               {
  148.                 /* Exit normally if this catcher can handle this
  149.                    exception.  The caller analyses the func return
  150.                    values.  */
  151.                 catcher_pop ();
  152.                 return 0;
  153.               }
  154.             /* The caller didn't request that the event be caught,
  155.                relay the event to the next containing
  156.                catch_errors().  */
  157.             catcher_pop ();
  158.             throw_exception (exception);
  159.           }
  160.         default:
  161.           internal_error (__FILE__, __LINE__, _("bad state"));
  162.         }
  163.     default:
  164.       internal_error (__FILE__, __LINE__, _("bad switch"));
  165.     }
  166. }

  167. int
  168. exceptions_state_mc_action_iter (void)
  169. {
  170.   return exceptions_state_mc (CATCH_ITER);
  171. }

  172. int
  173. exceptions_state_mc_action_iter_1 (void)
  174. {
  175.   return exceptions_state_mc (CATCH_ITER_1);
  176. }

  177. /* Return EXCEPTION to the nearest containing catch_errors().  */

  178. void
  179. throw_exception (struct gdb_exception exception)
  180. {
  181.   prepare_to_throw_exception ();

  182.   do_cleanups (all_cleanups ());

  183.   /* Jump to the containing catch_errors() call, communicating REASON
  184.      to that call via setjmp's return value.  Note that REASON can't
  185.      be zero, by definition in defs.h.  */
  186.   exceptions_state_mc (CATCH_THROWING);
  187.   *current_catcher->exception = exception;
  188.   SIGLONGJMP (current_catcher->buf, exception.reason);
  189. }

  190. /* A stack of exception messages.
  191.    This is needed to handle nested calls to throw_it: we don't want to
  192.    xfree space for a message before it's used.
  193.    This can happen if we throw an exception during a cleanup:
  194.    An outer TRY_CATCH may have an exception message it wants to print,
  195.    but while doing cleanups further calls to throw_it are made.

  196.    This is indexed by the size of the current_catcher list.
  197.    It is a dynamically allocated array so that we don't care how deeply
  198.    GDB nests its TRY_CATCHs.  */
  199. static char **exception_messages;

  200. /* The number of currently allocated entries in exception_messages.  */
  201. static int exception_messages_size;

  202. static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
  203. throw_it (enum return_reason reason, enum errors error, const char *fmt,
  204.           va_list ap)
  205. {
  206.   struct gdb_exception e;
  207.   char *new_message;
  208.   int depth = catcher_list_size ();

  209.   gdb_assert (depth > 0);

  210.   /* Note: The new message may use an old message's text.  */
  211.   new_message = xstrvprintf (fmt, ap);

  212.   if (depth > exception_messages_size)
  213.     {
  214.       int old_size = exception_messages_size;

  215.       exception_messages_size = depth + 10;
  216.       exception_messages = (char **) xrealloc (exception_messages,
  217.                                                exception_messages_size
  218.                                                * sizeof (char *));
  219.       memset (exception_messages + old_size, 0,
  220.               (exception_messages_size - old_size) * sizeof (char *));
  221.     }

  222.   xfree (exception_messages[depth - 1]);
  223.   exception_messages[depth - 1] = new_message;

  224.   /* Create the exception.  */
  225.   e.reason = reason;
  226.   e.error = error;
  227.   e.message = new_message;

  228.   /* Throw the exception.  */
  229.   throw_exception (e);
  230. }

  231. void
  232. throw_verror (enum errors error, const char *fmt, va_list ap)
  233. {
  234.   throw_it (RETURN_ERROR, error, fmt, ap);
  235. }

  236. void
  237. throw_vquit (const char *fmt, va_list ap)
  238. {
  239.   throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
  240. }

  241. void
  242. throw_error (enum errors error, const char *fmt, ...)
  243. {
  244.   va_list args;

  245.   va_start (args, fmt);
  246.   throw_verror (error, fmt, args);
  247.   va_end (args);
  248. }

  249. void
  250. throw_quit (const char *fmt, ...)
  251. {
  252.   va_list args;

  253.   va_start (args, fmt);
  254.   throw_vquit (fmt, args);
  255.   va_end (args);
  256. }