Simplify exception handling
[deliverable/binutils-gdb.git] / gdb / common / common-exceptions.c
CommitLineData
ff55e1b5
GB
1/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
42a4f53d 3 Copyright (C) 1986-2019 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 /* Back link. */
51 struct catcher *prev;
52};
53
54/* Where to go for throw_exception(). */
55static struct catcher *current_catcher;
56
173981bc 57jmp_buf *
492d29ea 58exceptions_state_mc_init (void)
ff55e1b5
GB
59{
60 struct catcher *new_catcher = XCNEW (struct catcher);
61
492d29ea
PA
62 /* Start with no exception. */
63 new_catcher->exception = exception_none;
ff55e1b5 64
ff55e1b5
GB
65 /* Push this new catcher on the top. */
66 new_catcher->prev = current_catcher;
67 current_catcher = new_catcher;
68 new_catcher->state = CATCHER_CREATED;
69
70 return &new_catcher->buf;
71}
72
73static void
74catcher_pop (void)
75{
76 struct catcher *old_catcher = current_catcher;
77
78 current_catcher = old_catcher->prev;
79
ff55e1b5
GB
80 xfree (old_catcher);
81}
82
83/* Catcher state machine. Returns non-zero if the m/c should be run
84 again, zero if it should abort. */
85
86static int
87exceptions_state_mc (enum catcher_action action)
88{
89 switch (current_catcher->state)
90 {
91 case CATCHER_CREATED:
92 switch (action)
93 {
94 case CATCH_ITER:
95 /* Allow the code to run the catcher. */
96 current_catcher->state = CATCHER_RUNNING;
97 return 1;
98 default:
99 internal_error (__FILE__, __LINE__, _("bad state"));
100 }
101 case CATCHER_RUNNING:
102 switch (action)
103 {
104 case CATCH_ITER:
492d29ea 105 /* No error/quit has occured. */
ff55e1b5
GB
106 return 0;
107 case CATCH_ITER_1:
108 current_catcher->state = CATCHER_RUNNING_1;
109 return 1;
110 case CATCH_THROWING:
111 current_catcher->state = CATCHER_ABORTING;
112 /* See also throw_exception. */
113 return 1;
114 default:
115 internal_error (__FILE__, __LINE__, _("bad switch"));
116 }
117 case CATCHER_RUNNING_1:
118 switch (action)
119 {
120 case CATCH_ITER:
121 /* The did a "break" from the inner while loop. */
ff55e1b5
GB
122 return 0;
123 case CATCH_ITER_1:
124 current_catcher->state = CATCHER_RUNNING;
125 return 0;
126 case CATCH_THROWING:
127 current_catcher->state = CATCHER_ABORTING;
128 /* See also throw_exception. */
129 return 1;
130 default:
131 internal_error (__FILE__, __LINE__, _("bad switch"));
132 }
133 case CATCHER_ABORTING:
134 switch (action)
135 {
136 case CATCH_ITER:
137 {
492d29ea
PA
138 /* Exit normally if this catcher can handle this
139 exception. The caller analyses the func return
140 values. */
141 return 0;
ff55e1b5
GB
142 }
143 default:
144 internal_error (__FILE__, __LINE__, _("bad state"));
145 }
146 default:
147 internal_error (__FILE__, __LINE__, _("bad switch"));
148 }
149}
150
492d29ea
PA
151int
152exceptions_state_mc_catch (struct gdb_exception *exception,
153 int mask)
154{
155 *exception = current_catcher->exception;
156 catcher_pop ();
157
158 if (exception->reason < 0)
159 {
160 if (mask & RETURN_MASK (exception->reason))
161 {
72df25b2 162 /* Exit normally and let the caller handle the
492d29ea
PA
163 exception. */
164 return 1;
165 }
166
167 /* The caller didn't request that the event be caught, relay the
89525768
PA
168 event to the next exception_catch/CATCH_SJLJ. */
169 throw_exception_sjlj (*exception);
492d29ea
PA
170 }
171
172 /* No exception was thrown. */
173 return 0;
174}
175
ff55e1b5
GB
176int
177exceptions_state_mc_action_iter (void)
178{
179 return exceptions_state_mc (CATCH_ITER);
180}
181
182int
183exceptions_state_mc_action_iter_1 (void)
184{
185 return exceptions_state_mc (CATCH_ITER_1);
186}
187
72df25b2
PA
188/* How many nested TRY blocks we have. See exception_messages and
189 throw_it. */
190
191static int try_scope_depth;
192
193/* Called on entry to a TRY scope. */
194
195void *
196exception_try_scope_entry (void)
197{
198 ++try_scope_depth;
fe7b42e5 199 return nullptr;
72df25b2
PA
200}
201
202/* Called on exit of a TRY scope, either normal exit or exception
203 exit. */
204
205void
206exception_try_scope_exit (void *saved_state)
207{
72df25b2
PA
208 --try_scope_depth;
209}
210
211/* Called by the default catch block. IOW, we'll get here before
212 jumping out to the next outermost scope an exception if a GDB
213 exception is not caught. */
214
215void
216exception_rethrow (void)
217{
72df25b2
PA
218 throw;
219}
220
221/* Copy the 'gdb_exception' portion of FROM to TO. */
222
223static void
224gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
225{
226 *to = *from;
227}
228
bf469271 229/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
ff55e1b5
GB
230
231void
89525768 232throw_exception_sjlj (struct gdb_exception exception)
ff55e1b5 233{
bf469271
PA
234 /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
235 that call via setjmp's return value. Note that REASON can't be
236 zero, by definition in common-exceptions.h. */
ff55e1b5 237 exceptions_state_mc (CATCH_THROWING);
492d29ea 238 current_catcher->exception = exception;
173981bc 239 longjmp (current_catcher->buf, exception.reason);
89525768
PA
240}
241
89525768
PA
242/* Implementation of throw_exception that uses C++ try/catch. */
243
244static ATTRIBUTE_NORETURN void
245throw_exception_cxx (struct gdb_exception exception)
246{
72df25b2
PA
247 if (exception.reason == RETURN_QUIT)
248 {
249 gdb_exception_RETURN_MASK_QUIT ex;
250
251 gdb_exception_sliced_copy (&ex, &exception);
252 throw ex;
253 }
254 else if (exception.reason == RETURN_ERROR)
255 {
256 gdb_exception_RETURN_MASK_ERROR ex;
257
258 gdb_exception_sliced_copy (&ex, &exception);
259 throw ex;
260 }
261 else
262 gdb_assert_not_reached ("invalid return reason");
89525768
PA
263}
264
89525768
PA
265void
266throw_exception (struct gdb_exception exception)
267{
89525768 268 throw_exception_cxx (exception);
ff55e1b5
GB
269}
270
271/* A stack of exception messages.
272 This is needed to handle nested calls to throw_it: we don't want to
273 xfree space for a message before it's used.
274 This can happen if we throw an exception during a cleanup:
275 An outer TRY_CATCH may have an exception message it wants to print,
276 but while doing cleanups further calls to throw_it are made.
277
278 This is indexed by the size of the current_catcher list.
279 It is a dynamically allocated array so that we don't care how deeply
280 GDB nests its TRY_CATCHs. */
281static char **exception_messages;
282
283/* The number of currently allocated entries in exception_messages. */
284static int exception_messages_size;
285
286static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
287throw_it (enum return_reason reason, enum errors error, const char *fmt,
288 va_list ap)
289{
290 struct gdb_exception e;
291 char *new_message;
72df25b2 292 int depth = try_scope_depth;
ff55e1b5
GB
293
294 gdb_assert (depth > 0);
295
296 /* Note: The new message may use an old message's text. */
297 new_message = xstrvprintf (fmt, ap);
298
299 if (depth > exception_messages_size)
300 {
301 int old_size = exception_messages_size;
302
303 exception_messages_size = depth + 10;
8d749320
SM
304 exception_messages = XRESIZEVEC (char *, exception_messages,
305 exception_messages_size);
ff55e1b5
GB
306 memset (exception_messages + old_size, 0,
307 (exception_messages_size - old_size) * sizeof (char *));
308 }
309
310 xfree (exception_messages[depth - 1]);
311 exception_messages[depth - 1] = new_message;
312
313 /* Create the exception. */
314 e.reason = reason;
315 e.error = error;
316 e.message = new_message;
317
318 /* Throw the exception. */
319 throw_exception (e);
320}
321
322void
323throw_verror (enum errors error, const char *fmt, va_list ap)
324{
325 throw_it (RETURN_ERROR, error, fmt, ap);
326}
327
328void
329throw_vquit (const char *fmt, va_list ap)
330{
331 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
332}
333
334void
335throw_error (enum errors error, const char *fmt, ...)
336{
337 va_list args;
338
339 va_start (args, fmt);
340 throw_verror (error, fmt, args);
341 va_end (args);
342}
343
344void
345throw_quit (const char *fmt, ...)
346{
347 va_list args;
348
349 va_start (args, fmt);
350 throw_vquit (fmt, args);
351 va_end (args);
352}
This page took 0.351481 seconds and 4 git commands to generate.