Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH
[deliverable/binutils-gdb.git] / gdb / common / common-exceptions.c
CommitLineData
ff55e1b5
GB
1/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
618f726f 3 Copyright (C) 1986-2016 Free Software Foundation, Inc.
ff55e1b5
GB
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20#include "common-defs.h"
21#include "common-exceptions.h"
ff55e1b5 22
44a8b4df 23const struct gdb_exception exception_none = { (enum return_reason) 0, GDB_NO_ERROR, NULL };
ad6aff7d 24
ff55e1b5
GB
25/* Possible catcher states. */
26enum catcher_state {
27 /* Initial state, a new catcher has just been created. */
28 CATCHER_CREATED,
29 /* The catch code is running. */
30 CATCHER_RUNNING,
31 CATCHER_RUNNING_1,
32 /* The catch code threw an exception. */
33 CATCHER_ABORTING
34};
35
36/* Possible catcher actions. */
37enum catcher_action {
38 CATCH_ITER,
39 CATCH_ITER_1,
40 CATCH_THROWING
41};
42
43struct catcher
44{
45 enum catcher_state state;
46 /* Jump buffer pointing back at the exception handler. */
173981bc 47 jmp_buf buf;
ff55e1b5 48 /* Status buffer belonging to the exception handler. */
492d29ea 49 struct gdb_exception exception;
ff55e1b5
GB
50 struct cleanup *saved_cleanup_chain;
51 /* Back link. */
52 struct catcher *prev;
53};
54
55/* Where to go for throw_exception(). */
56static struct catcher *current_catcher;
57
89525768
PA
58#if GDB_XCPT == GDB_XCPT_SJMP
59
ff55e1b5
GB
60/* Return length of current_catcher list. */
61
62static int
63catcher_list_size (void)
64{
65 int size;
66 struct catcher *catcher;
67
68 for (size = 0, catcher = current_catcher;
69 catcher != NULL;
70 catcher = catcher->prev)
71 ++size;
72
73 return size;
74}
75
89525768
PA
76#endif
77
173981bc 78jmp_buf *
492d29ea 79exceptions_state_mc_init (void)
ff55e1b5
GB
80{
81 struct catcher *new_catcher = XCNEW (struct catcher);
82
492d29ea
PA
83 /* Start with no exception. */
84 new_catcher->exception = exception_none;
ff55e1b5
GB
85
86 /* Prevent error/quit during FUNC from calling cleanups established
87 prior to here. */
88 new_catcher->saved_cleanup_chain = save_cleanups ();
89
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;
94
95 return &new_catcher->buf;
96}
97
98static void
99catcher_pop (void)
100{
101 struct catcher *old_catcher = current_catcher;
102
103 current_catcher = old_catcher->prev;
104
105 /* Restore the cleanup chain, the error/quit messages, and the uiout
106 builder, to their original states. */
107
108 restore_cleanups (old_catcher->saved_cleanup_chain);
109
110 xfree (old_catcher);
111}
112
113/* Catcher state machine. Returns non-zero if the m/c should be run
114 again, zero if it should abort. */
115
116static int
117exceptions_state_mc (enum catcher_action action)
118{
119 switch (current_catcher->state)
120 {
121 case CATCHER_CREATED:
122 switch (action)
123 {
124 case CATCH_ITER:
125 /* Allow the code to run the catcher. */
126 current_catcher->state = CATCHER_RUNNING;
127 return 1;
128 default:
129 internal_error (__FILE__, __LINE__, _("bad state"));
130 }
131 case CATCHER_RUNNING:
132 switch (action)
133 {
134 case CATCH_ITER:
492d29ea 135 /* No error/quit has occured. */
ff55e1b5
GB
136 return 0;
137 case CATCH_ITER_1:
138 current_catcher->state = CATCHER_RUNNING_1;
139 return 1;
140 case CATCH_THROWING:
141 current_catcher->state = CATCHER_ABORTING;
142 /* See also throw_exception. */
143 return 1;
144 default:
145 internal_error (__FILE__, __LINE__, _("bad switch"));
146 }
147 case CATCHER_RUNNING_1:
148 switch (action)
149 {
150 case CATCH_ITER:
151 /* The did a "break" from the inner while loop. */
ff55e1b5
GB
152 return 0;
153 case CATCH_ITER_1:
154 current_catcher->state = CATCHER_RUNNING;
155 return 0;
156 case CATCH_THROWING:
157 current_catcher->state = CATCHER_ABORTING;
158 /* See also throw_exception. */
159 return 1;
160 default:
161 internal_error (__FILE__, __LINE__, _("bad switch"));
162 }
163 case CATCHER_ABORTING:
164 switch (action)
165 {
166 case CATCH_ITER:
167 {
492d29ea
PA
168 /* Exit normally if this catcher can handle this
169 exception. The caller analyses the func return
170 values. */
171 return 0;
ff55e1b5
GB
172 }
173 default:
174 internal_error (__FILE__, __LINE__, _("bad state"));
175 }
176 default:
177 internal_error (__FILE__, __LINE__, _("bad switch"));
178 }
179}
180
492d29ea
PA
181int
182exceptions_state_mc_catch (struct gdb_exception *exception,
183 int mask)
184{
185 *exception = current_catcher->exception;
186 catcher_pop ();
187
188 if (exception->reason < 0)
189 {
190 if (mask & RETURN_MASK (exception->reason))
191 {
72df25b2 192 /* Exit normally and let the caller handle the
492d29ea
PA
193 exception. */
194 return 1;
195 }
196
197 /* The caller didn't request that the event be caught, relay the
89525768
PA
198 event to the next exception_catch/CATCH_SJLJ. */
199 throw_exception_sjlj (*exception);
492d29ea
PA
200 }
201
202 /* No exception was thrown. */
203 return 0;
204}
205
ff55e1b5
GB
206int
207exceptions_state_mc_action_iter (void)
208{
209 return exceptions_state_mc (CATCH_ITER);
210}
211
212int
213exceptions_state_mc_action_iter_1 (void)
214{
215 return exceptions_state_mc (CATCH_ITER_1);
216}
217
89525768 218#if GDB_XCPT != GDB_XCPT_SJMP
72df25b2
PA
219
220/* How many nested TRY blocks we have. See exception_messages and
221 throw_it. */
222
223static int try_scope_depth;
224
225/* Called on entry to a TRY scope. */
226
227void *
228exception_try_scope_entry (void)
229{
230 ++try_scope_depth;
231 return (void *) save_cleanups ();
232}
233
234/* Called on exit of a TRY scope, either normal exit or exception
235 exit. */
236
237void
238exception_try_scope_exit (void *saved_state)
239{
240 restore_cleanups ((struct cleanup *) saved_state);
241 --try_scope_depth;
242}
243
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. */
247
248void
249exception_rethrow (void)
250{
251 /* Run this scope's cleanups before re-throwing to the next
252 outermost scope. */
72df25b2
PA
253 do_cleanups (all_cleanups ());
254 throw;
255}
256
257/* Copy the 'gdb_exception' portion of FROM to TO. */
258
259static void
260gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
261{
262 *to = *from;
263}
264
eec461d0 265#endif /* !GDB_XCPT_SJMP */
72df25b2 266
ff55e1b5
GB
267/* Return EXCEPTION to the nearest containing catch_errors(). */
268
269void
89525768 270throw_exception_sjlj (struct gdb_exception exception)
ff55e1b5 271{
ff55e1b5
GB
272 do_cleanups (all_cleanups ());
273
274 /* Jump to the containing catch_errors() call, communicating REASON
275 to that call via setjmp's return value. Note that REASON can't
276 be zero, by definition in defs.h. */
277 exceptions_state_mc (CATCH_THROWING);
492d29ea 278 current_catcher->exception = exception;
173981bc 279 longjmp (current_catcher->buf, exception.reason);
89525768
PA
280}
281
282#if GDB_XCPT != GDB_XCPT_SJMP
283
284/* Implementation of throw_exception that uses C++ try/catch. */
285
286static ATTRIBUTE_NORETURN void
287throw_exception_cxx (struct gdb_exception exception)
288{
289 do_cleanups (all_cleanups ());
290
72df25b2
PA
291 if (exception.reason == RETURN_QUIT)
292 {
293 gdb_exception_RETURN_MASK_QUIT ex;
294
295 gdb_exception_sliced_copy (&ex, &exception);
296 throw ex;
297 }
298 else if (exception.reason == RETURN_ERROR)
299 {
300 gdb_exception_RETURN_MASK_ERROR ex;
301
302 gdb_exception_sliced_copy (&ex, &exception);
303 throw ex;
304 }
305 else
306 gdb_assert_not_reached ("invalid return reason");
89525768
PA
307}
308
309#endif
310
311void
312throw_exception (struct gdb_exception exception)
313{
314#if GDB_XCPT == GDB_XCPT_SJMP
315 throw_exception_sjlj (exception);
316#else
317 throw_exception_cxx (exception);
72df25b2 318#endif
ff55e1b5
GB
319}
320
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.
327
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. */
331static char **exception_messages;
332
333/* The number of currently allocated entries in exception_messages. */
334static int exception_messages_size;
335
336static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
337throw_it (enum return_reason reason, enum errors error, const char *fmt,
338 va_list ap)
339{
340 struct gdb_exception e;
341 char *new_message;
eec461d0 342#if GDB_XCPT == GDB_XCPT_SJMP
ff55e1b5 343 int depth = catcher_list_size ();
72df25b2
PA
344#else
345 int depth = try_scope_depth;
346#endif
ff55e1b5
GB
347
348 gdb_assert (depth > 0);
349
350 /* Note: The new message may use an old message's text. */
351 new_message = xstrvprintf (fmt, ap);
352
353 if (depth > exception_messages_size)
354 {
355 int old_size = exception_messages_size;
356
357 exception_messages_size = depth + 10;
8d749320
SM
358 exception_messages = XRESIZEVEC (char *, exception_messages,
359 exception_messages_size);
ff55e1b5
GB
360 memset (exception_messages + old_size, 0,
361 (exception_messages_size - old_size) * sizeof (char *));
362 }
363
364 xfree (exception_messages[depth - 1]);
365 exception_messages[depth - 1] = new_message;
366
367 /* Create the exception. */
368 e.reason = reason;
369 e.error = error;
370 e.message = new_message;
371
372 /* Throw the exception. */
373 throw_exception (e);
374}
375
376void
377throw_verror (enum errors error, const char *fmt, va_list ap)
378{
379 throw_it (RETURN_ERROR, error, fmt, ap);
380}
381
382void
383throw_vquit (const char *fmt, va_list ap)
384{
385 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
386}
387
388void
389throw_error (enum errors error, const char *fmt, ...)
390{
391 va_list args;
392
393 va_start (args, fmt);
394 throw_verror (error, fmt, args);
395 va_end (args);
396}
397
398void
399throw_quit (const char *fmt, ...)
400{
401 va_list args;
402
403 va_start (args, fmt);
404 throw_vquit (fmt, args);
405 va_end (args);
406}
This page took 0.157347 seconds and 4 git commands to generate.