Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH
[deliverable/binutils-gdb.git] / gdb / common / common-exceptions.c
1 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
3 Copyright (C) 1986-2016 Free Software Foundation, Inc.
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"
22
23 const struct gdb_exception exception_none = { (enum return_reason) 0, GDB_NO_ERROR, NULL };
24
25 /* Possible catcher states. */
26 enum 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. */
37 enum catcher_action {
38 CATCH_ITER,
39 CATCH_ITER_1,
40 CATCH_THROWING
41 };
42
43 struct catcher
44 {
45 enum catcher_state state;
46 /* Jump buffer pointing back at the exception handler. */
47 jmp_buf buf;
48 /* Status buffer belonging to the exception handler. */
49 struct gdb_exception exception;
50 struct cleanup *saved_cleanup_chain;
51 /* Back link. */
52 struct catcher *prev;
53 };
54
55 /* Where to go for throw_exception(). */
56 static struct catcher *current_catcher;
57
58 #if GDB_XCPT == GDB_XCPT_SJMP
59
60 /* Return length of current_catcher list. */
61
62 static int
63 catcher_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
76 #endif
77
78 jmp_buf *
79 exceptions_state_mc_init (void)
80 {
81 struct catcher *new_catcher = XCNEW (struct catcher);
82
83 /* Start with no exception. */
84 new_catcher->exception = exception_none;
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
98 static void
99 catcher_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
116 static int
117 exceptions_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:
135 /* No error/quit has occured. */
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. */
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 {
168 /* Exit normally if this catcher can handle this
169 exception. The caller analyses the func return
170 values. */
171 return 0;
172 }
173 default:
174 internal_error (__FILE__, __LINE__, _("bad state"));
175 }
176 default:
177 internal_error (__FILE__, __LINE__, _("bad switch"));
178 }
179 }
180
181 int
182 exceptions_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 {
192 /* Exit normally and let the caller handle the
193 exception. */
194 return 1;
195 }
196
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);
200 }
201
202 /* No exception was thrown. */
203 return 0;
204 }
205
206 int
207 exceptions_state_mc_action_iter (void)
208 {
209 return exceptions_state_mc (CATCH_ITER);
210 }
211
212 int
213 exceptions_state_mc_action_iter_1 (void)
214 {
215 return exceptions_state_mc (CATCH_ITER_1);
216 }
217
218 #if GDB_XCPT != GDB_XCPT_SJMP
219
220 /* How many nested TRY blocks we have. See exception_messages and
221 throw_it. */
222
223 static int try_scope_depth;
224
225 /* Called on entry to a TRY scope. */
226
227 void *
228 exception_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
237 void
238 exception_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
248 void
249 exception_rethrow (void)
250 {
251 /* Run this scope's cleanups before re-throwing to the next
252 outermost scope. */
253 do_cleanups (all_cleanups ());
254 throw;
255 }
256
257 /* Copy the 'gdb_exception' portion of FROM to TO. */
258
259 static void
260 gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
261 {
262 *to = *from;
263 }
264
265 #endif /* !GDB_XCPT_SJMP */
266
267 /* Return EXCEPTION to the nearest containing catch_errors(). */
268
269 void
270 throw_exception_sjlj (struct gdb_exception exception)
271 {
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);
278 current_catcher->exception = exception;
279 longjmp (current_catcher->buf, exception.reason);
280 }
281
282 #if GDB_XCPT != GDB_XCPT_SJMP
283
284 /* Implementation of throw_exception that uses C++ try/catch. */
285
286 static ATTRIBUTE_NORETURN void
287 throw_exception_cxx (struct gdb_exception exception)
288 {
289 do_cleanups (all_cleanups ());
290
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");
307 }
308
309 #endif
310
311 void
312 throw_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);
318 #endif
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. */
331 static char **exception_messages;
332
333 /* The number of currently allocated entries in exception_messages. */
334 static int exception_messages_size;
335
336 static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
337 throw_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;
342 #if GDB_XCPT == GDB_XCPT_SJMP
343 int depth = catcher_list_size ();
344 #else
345 int depth = try_scope_depth;
346 #endif
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;
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 *));
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
376 void
377 throw_verror (enum errors error, const char *fmt, va_list ap)
378 {
379 throw_it (RETURN_ERROR, error, fmt, ap);
380 }
381
382 void
383 throw_vquit (const char *fmt, va_list ap)
384 {
385 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
386 }
387
388 void
389 throw_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
398 void
399 throw_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.04122 seconds and 5 git commands to generate.