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
;
54 /* Where to go for throw_exception(). */
55 static struct catcher
*current_catcher
;
57 #if GDB_XCPT == GDB_XCPT_SJMP
59 /* Return length of current_catcher list. */
62 catcher_list_size (void)
65 struct catcher
*catcher
;
67 for (size
= 0, catcher
= current_catcher
;
69 catcher
= catcher
->prev
)
78 exceptions_state_mc_init (void)
80 struct catcher
*new_catcher
= XCNEW (struct catcher
);
82 /* Start with no exception. */
83 new_catcher
->exception
= exception_none
;
85 /* Push this new catcher on the top. */
86 new_catcher
->prev
= current_catcher
;
87 current_catcher
= new_catcher
;
88 new_catcher
->state
= CATCHER_CREATED
;
90 return &new_catcher
->buf
;
96 struct catcher
*old_catcher
= current_catcher
;
98 current_catcher
= old_catcher
->prev
;
103 /* Catcher state machine. Returns non-zero if the m/c should be run
104 again, zero if it should abort. */
107 exceptions_state_mc (enum catcher_action action
)
109 switch (current_catcher
->state
)
111 case CATCHER_CREATED
:
115 /* Allow the code to run the catcher. */
116 current_catcher
->state
= CATCHER_RUNNING
;
119 internal_error (__FILE__
, __LINE__
, _("bad state"));
121 case CATCHER_RUNNING
:
125 /* No error/quit has occured. */
128 current_catcher
->state
= CATCHER_RUNNING_1
;
131 current_catcher
->state
= CATCHER_ABORTING
;
132 /* See also throw_exception. */
135 internal_error (__FILE__
, __LINE__
, _("bad switch"));
137 case CATCHER_RUNNING_1
:
141 /* The did a "break" from the inner while loop. */
144 current_catcher
->state
= CATCHER_RUNNING
;
147 current_catcher
->state
= CATCHER_ABORTING
;
148 /* See also throw_exception. */
151 internal_error (__FILE__
, __LINE__
, _("bad switch"));
153 case CATCHER_ABORTING
:
158 /* Exit normally if this catcher can handle this
159 exception. The caller analyses the func return
164 internal_error (__FILE__
, __LINE__
, _("bad state"));
167 internal_error (__FILE__
, __LINE__
, _("bad switch"));
172 exceptions_state_mc_catch (struct gdb_exception
*exception
,
175 *exception
= current_catcher
->exception
;
178 if (exception
->reason
< 0)
180 if (mask
& RETURN_MASK (exception
->reason
))
182 /* Exit normally and let the caller handle the
187 /* The caller didn't request that the event be caught, relay the
188 event to the next exception_catch/CATCH_SJLJ. */
189 throw_exception_sjlj (*exception
);
192 /* No exception was thrown. */
197 exceptions_state_mc_action_iter (void)
199 return exceptions_state_mc (CATCH_ITER
);
203 exceptions_state_mc_action_iter_1 (void)
205 return exceptions_state_mc (CATCH_ITER_1
);
208 #if GDB_XCPT != GDB_XCPT_SJMP
210 /* How many nested TRY blocks we have. See exception_messages and
213 static int try_scope_depth
;
215 /* Called on entry to a TRY scope. */
218 exception_try_scope_entry (void)
224 /* Called on exit of a TRY scope, either normal exit or exception
228 exception_try_scope_exit (void *saved_state
)
233 /* Called by the default catch block. IOW, we'll get here before
234 jumping out to the next outermost scope an exception if a GDB
235 exception is not caught. */
238 exception_rethrow (void)
243 /* Copy the 'gdb_exception' portion of FROM to TO. */
246 gdb_exception_sliced_copy (struct gdb_exception
*to
, const struct gdb_exception
*from
)
251 #endif /* !GDB_XCPT_SJMP */
253 /* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
256 throw_exception_sjlj (struct gdb_exception exception
)
258 /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
259 that call via setjmp's return value. Note that REASON can't be
260 zero, by definition in common-exceptions.h. */
261 exceptions_state_mc (CATCH_THROWING
);
262 current_catcher
->exception
= exception
;
263 longjmp (current_catcher
->buf
, exception
.reason
);
266 #if GDB_XCPT != GDB_XCPT_SJMP
268 /* Implementation of throw_exception that uses C++ try/catch. */
270 static ATTRIBUTE_NORETURN
void
271 throw_exception_cxx (struct gdb_exception exception
)
273 if (exception
.reason
== RETURN_QUIT
)
275 gdb_exception_RETURN_MASK_QUIT ex
;
277 gdb_exception_sliced_copy (&ex
, &exception
);
280 else if (exception
.reason
== RETURN_ERROR
)
282 gdb_exception_RETURN_MASK_ERROR ex
;
284 gdb_exception_sliced_copy (&ex
, &exception
);
288 gdb_assert_not_reached ("invalid return reason");
294 throw_exception (struct gdb_exception exception
)
296 #if GDB_XCPT == GDB_XCPT_SJMP
297 throw_exception_sjlj (exception
);
299 throw_exception_cxx (exception
);
303 /* A stack of exception messages.
304 This is needed to handle nested calls to throw_it: we don't want to
305 xfree space for a message before it's used.
306 This can happen if we throw an exception during a cleanup:
307 An outer TRY_CATCH may have an exception message it wants to print,
308 but while doing cleanups further calls to throw_it are made.
310 This is indexed by the size of the current_catcher list.
311 It is a dynamically allocated array so that we don't care how deeply
312 GDB nests its TRY_CATCHs. */
313 static char **exception_messages
;
315 /* The number of currently allocated entries in exception_messages. */
316 static int exception_messages_size
;
318 static void ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF (3, 0)
319 throw_it (enum return_reason reason
, enum errors error
, const char *fmt
,
322 struct gdb_exception e
;
324 #if GDB_XCPT == GDB_XCPT_SJMP
325 int depth
= catcher_list_size ();
327 int depth
= try_scope_depth
;
330 gdb_assert (depth
> 0);
332 /* Note: The new message may use an old message's text. */
333 new_message
= xstrvprintf (fmt
, ap
);
335 if (depth
> exception_messages_size
)
337 int old_size
= exception_messages_size
;
339 exception_messages_size
= depth
+ 10;
340 exception_messages
= XRESIZEVEC (char *, exception_messages
,
341 exception_messages_size
);
342 memset (exception_messages
+ old_size
, 0,
343 (exception_messages_size
- old_size
) * sizeof (char *));
346 xfree (exception_messages
[depth
- 1]);
347 exception_messages
[depth
- 1] = new_message
;
349 /* Create the exception. */
352 e
.message
= new_message
;
354 /* Throw the exception. */
359 throw_verror (enum errors error
, const char *fmt
, va_list ap
)
361 throw_it (RETURN_ERROR
, error
, fmt
, ap
);
365 throw_vquit (const char *fmt
, va_list ap
)
367 throw_it (RETURN_QUIT
, GDB_NO_ERROR
, fmt
, ap
);
371 throw_error (enum errors error
, const char *fmt
, ...)
375 va_start (args
, fmt
);
376 throw_verror (error
, fmt
, args
);
381 throw_quit (const char *fmt
, ...)
385 va_start (args
, fmt
);
386 throw_vquit (fmt
, args
);