1 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
3 Copyright (C) 1986-2019 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "common-defs.h"
21 #include "common-exceptions.h"
23 const struct gdb_exception exception_none = { (enum return_reason) 0, GDB_NO_ERROR, NULL };
25 /* Possible catcher states. */
27 /* Initial state, a new catcher has just been created. */
29 /* The catch code is running. */
32 /* The catch code threw an exception. */
36 /* Possible catcher actions. */
45 enum catcher_state state;
46 /* Jump buffer pointing back at the exception handler. */
48 /* Status buffer belonging to the exception handler. */
49 struct gdb_exception exception;
50 struct cleanup *saved_cleanup_chain;
55 /* Where to go for throw_exception(). */
56 static struct catcher *current_catcher;
58 #if GDB_XCPT == GDB_XCPT_SJMP
60 /* Return length of current_catcher list. */
63 catcher_list_size (void)
66 struct catcher *catcher;
68 for (size = 0, catcher = current_catcher;
70 catcher = catcher->prev)
79 exceptions_state_mc_init (void)
81 struct catcher *new_catcher = XCNEW (struct catcher);
83 /* Start with no exception. */
84 new_catcher->exception = exception_none;
86 /* Prevent error/quit during FUNC from calling cleanups established
88 new_catcher->saved_cleanup_chain = save_cleanups ();
90 /* Push this new catcher on the top. */
91 new_catcher->prev = current_catcher;
92 current_catcher = new_catcher;
93 new_catcher->state = CATCHER_CREATED;
95 return &new_catcher->buf;
101 struct catcher *old_catcher = current_catcher;
103 current_catcher = old_catcher->prev;
105 /* Restore the cleanup chain, the error/quit messages, and the uiout
106 builder, to their original states. */
108 restore_cleanups (old_catcher->saved_cleanup_chain);
113 /* Catcher state machine. Returns non-zero if the m/c should be run
114 again, zero if it should abort. */
117 exceptions_state_mc (enum catcher_action action)
119 switch (current_catcher->state)
121 case CATCHER_CREATED:
125 /* Allow the code to run the catcher. */
126 current_catcher->state = CATCHER_RUNNING;
129 internal_error (__FILE__, __LINE__, _("bad state"));
131 case CATCHER_RUNNING:
135 /* No error/quit has occured. */
138 current_catcher->state = CATCHER_RUNNING_1;
141 current_catcher->state = CATCHER_ABORTING;
142 /* See also throw_exception. */
145 internal_error (__FILE__, __LINE__, _("bad switch"));
147 case CATCHER_RUNNING_1:
151 /* The did a "break" from the inner while loop. */
154 current_catcher->state = CATCHER_RUNNING;
157 current_catcher->state = CATCHER_ABORTING;
158 /* See also throw_exception. */
161 internal_error (__FILE__, __LINE__, _("bad switch"));
163 case CATCHER_ABORTING:
168 /* Exit normally if this catcher can handle this
169 exception. The caller analyses the func return
174 internal_error (__FILE__, __LINE__, _("bad state"));
177 internal_error (__FILE__, __LINE__, _("bad switch"));
182 exceptions_state_mc_catch (struct gdb_exception *exception,
185 *exception = current_catcher->exception;
188 if (exception->reason < 0)
190 if (mask & RETURN_MASK (exception->reason))
192 /* Exit normally and let the caller handle the
197 /* The caller didn't request that the event be caught, relay the
198 event to the next exception_catch/CATCH_SJLJ. */
199 throw_exception_sjlj (*exception);
202 /* No exception was thrown. */
207 exceptions_state_mc_action_iter (void)
209 return exceptions_state_mc (CATCH_ITER);
213 exceptions_state_mc_action_iter_1 (void)
215 return exceptions_state_mc (CATCH_ITER_1);
218 #if GDB_XCPT != GDB_XCPT_SJMP
220 /* How many nested TRY blocks we have. See exception_messages and
223 static int try_scope_depth;
225 /* Called on entry to a TRY scope. */
228 exception_try_scope_entry (void)
231 return (void *) save_cleanups ();
234 /* Called on exit of a TRY scope, either normal exit or exception
238 exception_try_scope_exit (void *saved_state)
240 restore_cleanups ((struct cleanup *) saved_state);
244 /* Called by the default catch block. IOW, we'll get here before
245 jumping out to the next outermost scope an exception if a GDB
246 exception is not caught. */
249 exception_rethrow (void)
251 /* Run this scope's cleanups before re-throwing to the next
253 do_cleanups (all_cleanups ());
257 /* Copy the 'gdb_exception' portion of FROM to TO. */
260 gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
265 #endif /* !GDB_XCPT_SJMP */
267 /* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
270 throw_exception_sjlj (struct gdb_exception exception)
272 do_cleanups (all_cleanups ());
274 /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
275 that call via setjmp's return value. Note that REASON can't be
276 zero, by definition in common-exceptions.h. */
277 exceptions_state_mc (CATCH_THROWING);
278 current_catcher->exception = exception;
279 longjmp (current_catcher->buf, exception.reason);
282 #if GDB_XCPT != GDB_XCPT_SJMP
284 /* Implementation of throw_exception that uses C++ try/catch. */
286 static ATTRIBUTE_NORETURN void
287 throw_exception_cxx (struct gdb_exception exception)
289 do_cleanups (all_cleanups ());
291 if (exception.reason == RETURN_QUIT)
293 gdb_exception_RETURN_MASK_QUIT ex;
295 gdb_exception_sliced_copy (&ex, &exception);
298 else if (exception.reason == RETURN_ERROR)
300 gdb_exception_RETURN_MASK_ERROR ex;
302 gdb_exception_sliced_copy (&ex, &exception);
306 gdb_assert_not_reached ("invalid return reason");
312 throw_exception (struct gdb_exception exception)
314 #if GDB_XCPT == GDB_XCPT_SJMP
315 throw_exception_sjlj (exception);
317 throw_exception_cxx (exception);
321 /* A stack of exception messages.
322 This is needed to handle nested calls to throw_it: we don't want to
323 xfree space for a message before it's used.
324 This can happen if we throw an exception during a cleanup:
325 An outer TRY_CATCH may have an exception message it wants to print,
326 but while doing cleanups further calls to throw_it are made.
328 This is indexed by the size of the current_catcher list.
329 It is a dynamically allocated array so that we don't care how deeply
330 GDB nests its TRY_CATCHs. */
331 static char **exception_messages;
333 /* The number of currently allocated entries in exception_messages. */
334 static int exception_messages_size;
336 static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
337 throw_it (enum return_reason reason, enum errors error, const char *fmt,
340 struct gdb_exception e;
342 #if GDB_XCPT == GDB_XCPT_SJMP
343 int depth = catcher_list_size ();
345 int depth = try_scope_depth;
348 gdb_assert (depth > 0);
350 /* Note: The new message may use an old message's text. */
351 new_message = xstrvprintf (fmt, ap);
353 if (depth > exception_messages_size)
355 int old_size = exception_messages_size;
357 exception_messages_size = depth + 10;
358 exception_messages = XRESIZEVEC (char *, exception_messages,
359 exception_messages_size);
360 memset (exception_messages + old_size, 0,
361 (exception_messages_size - old_size) * sizeof (char *));
364 xfree (exception_messages[depth - 1]);
365 exception_messages[depth - 1] = new_message;
367 /* Create the exception. */
370 e.message = new_message;
372 /* Throw the exception. */
377 throw_verror (enum errors error, const char *fmt, va_list ap)
379 throw_it (RETURN_ERROR, error, fmt, ap);
383 throw_vquit (const char *fmt, va_list ap)
385 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
389 throw_error (enum errors error, const char *fmt, ...)
393 va_start (args, fmt);
394 throw_verror (error, fmt, args);
399 throw_quit (const char *fmt, ...)
403 va_start (args, fmt);
404 throw_vquit (fmt, args);