kill volatile struct gdb_exception
[deliverable/binutils-gdb.git] / gdb / common / common-exceptions.c
CommitLineData
ff55e1b5
GB
1/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
32d0add0 3 Copyright (C) 1986-2015 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
ad6aff7d
PA
23const struct gdb_exception exception_none = { 0, GDB_NO_ERROR, NULL };
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. */
47 SIGJMP_BUF buf;
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
58/* Return length of current_catcher list. */
59
60static int
61catcher_list_size (void)
62{
63 int size;
64 struct catcher *catcher;
65
66 for (size = 0, catcher = current_catcher;
67 catcher != NULL;
68 catcher = catcher->prev)
69 ++size;
70
71 return size;
72}
73
74SIGJMP_BUF *
492d29ea 75exceptions_state_mc_init (void)
ff55e1b5
GB
76{
77 struct catcher *new_catcher = XCNEW (struct catcher);
78
492d29ea
PA
79 /* Start with no exception. */
80 new_catcher->exception = exception_none;
ff55e1b5
GB
81
82 /* Prevent error/quit during FUNC from calling cleanups established
83 prior to here. */
84 new_catcher->saved_cleanup_chain = save_cleanups ();
85
86 /* Push this new catcher on the top. */
87 new_catcher->prev = current_catcher;
88 current_catcher = new_catcher;
89 new_catcher->state = CATCHER_CREATED;
90
91 return &new_catcher->buf;
92}
93
94static void
95catcher_pop (void)
96{
97 struct catcher *old_catcher = current_catcher;
98
99 current_catcher = old_catcher->prev;
100
101 /* Restore the cleanup chain, the error/quit messages, and the uiout
102 builder, to their original states. */
103
104 restore_cleanups (old_catcher->saved_cleanup_chain);
105
106 xfree (old_catcher);
107}
108
109/* Catcher state machine. Returns non-zero if the m/c should be run
110 again, zero if it should abort. */
111
112static int
113exceptions_state_mc (enum catcher_action action)
114{
115 switch (current_catcher->state)
116 {
117 case CATCHER_CREATED:
118 switch (action)
119 {
120 case CATCH_ITER:
121 /* Allow the code to run the catcher. */
122 current_catcher->state = CATCHER_RUNNING;
123 return 1;
124 default:
125 internal_error (__FILE__, __LINE__, _("bad state"));
126 }
127 case CATCHER_RUNNING:
128 switch (action)
129 {
130 case CATCH_ITER:
492d29ea 131 /* No error/quit has occured. */
ff55e1b5
GB
132 return 0;
133 case CATCH_ITER_1:
134 current_catcher->state = CATCHER_RUNNING_1;
135 return 1;
136 case CATCH_THROWING:
137 current_catcher->state = CATCHER_ABORTING;
138 /* See also throw_exception. */
139 return 1;
140 default:
141 internal_error (__FILE__, __LINE__, _("bad switch"));
142 }
143 case CATCHER_RUNNING_1:
144 switch (action)
145 {
146 case CATCH_ITER:
147 /* The did a "break" from the inner while loop. */
ff55e1b5
GB
148 return 0;
149 case CATCH_ITER_1:
150 current_catcher->state = CATCHER_RUNNING;
151 return 0;
152 case CATCH_THROWING:
153 current_catcher->state = CATCHER_ABORTING;
154 /* See also throw_exception. */
155 return 1;
156 default:
157 internal_error (__FILE__, __LINE__, _("bad switch"));
158 }
159 case CATCHER_ABORTING:
160 switch (action)
161 {
162 case CATCH_ITER:
163 {
492d29ea
PA
164 /* Exit normally if this catcher can handle this
165 exception. The caller analyses the func return
166 values. */
167 return 0;
ff55e1b5
GB
168 }
169 default:
170 internal_error (__FILE__, __LINE__, _("bad state"));
171 }
172 default:
173 internal_error (__FILE__, __LINE__, _("bad switch"));
174 }
175}
176
492d29ea
PA
177int
178exceptions_state_mc_catch (struct gdb_exception *exception,
179 int mask)
180{
181 *exception = current_catcher->exception;
182 catcher_pop ();
183
184 if (exception->reason < 0)
185 {
186 if (mask & RETURN_MASK (exception->reason))
187 {
188 /* Exit normally and let the called handle the
189 exception. */
190 return 1;
191 }
192
193 /* The caller didn't request that the event be caught, relay the
194 event to the next exception_catch/CATCH. */
195 throw_exception (*exception);
196 }
197
198 /* No exception was thrown. */
199 return 0;
200}
201
ff55e1b5
GB
202int
203exceptions_state_mc_action_iter (void)
204{
205 return exceptions_state_mc (CATCH_ITER);
206}
207
208int
209exceptions_state_mc_action_iter_1 (void)
210{
211 return exceptions_state_mc (CATCH_ITER_1);
212}
213
214/* Return EXCEPTION to the nearest containing catch_errors(). */
215
216void
217throw_exception (struct gdb_exception exception)
218{
219 prepare_to_throw_exception ();
220
221 do_cleanups (all_cleanups ());
222
223 /* Jump to the containing catch_errors() call, communicating REASON
224 to that call via setjmp's return value. Note that REASON can't
225 be zero, by definition in defs.h. */
226 exceptions_state_mc (CATCH_THROWING);
492d29ea 227 current_catcher->exception = exception;
ff55e1b5
GB
228 SIGLONGJMP (current_catcher->buf, exception.reason);
229}
230
231/* A stack of exception messages.
232 This is needed to handle nested calls to throw_it: we don't want to
233 xfree space for a message before it's used.
234 This can happen if we throw an exception during a cleanup:
235 An outer TRY_CATCH may have an exception message it wants to print,
236 but while doing cleanups further calls to throw_it are made.
237
238 This is indexed by the size of the current_catcher list.
239 It is a dynamically allocated array so that we don't care how deeply
240 GDB nests its TRY_CATCHs. */
241static char **exception_messages;
242
243/* The number of currently allocated entries in exception_messages. */
244static int exception_messages_size;
245
246static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
247throw_it (enum return_reason reason, enum errors error, const char *fmt,
248 va_list ap)
249{
250 struct gdb_exception e;
251 char *new_message;
252 int depth = catcher_list_size ();
253
254 gdb_assert (depth > 0);
255
256 /* Note: The new message may use an old message's text. */
257 new_message = xstrvprintf (fmt, ap);
258
259 if (depth > exception_messages_size)
260 {
261 int old_size = exception_messages_size;
262
263 exception_messages_size = depth + 10;
264 exception_messages = (char **) xrealloc (exception_messages,
265 exception_messages_size
266 * sizeof (char *));
267 memset (exception_messages + old_size, 0,
268 (exception_messages_size - old_size) * sizeof (char *));
269 }
270
271 xfree (exception_messages[depth - 1]);
272 exception_messages[depth - 1] = new_message;
273
274 /* Create the exception. */
275 e.reason = reason;
276 e.error = error;
277 e.message = new_message;
278
279 /* Throw the exception. */
280 throw_exception (e);
281}
282
283void
284throw_verror (enum errors error, const char *fmt, va_list ap)
285{
286 throw_it (RETURN_ERROR, error, fmt, ap);
287}
288
289void
290throw_vquit (const char *fmt, va_list ap)
291{
292 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
293}
294
295void
296throw_error (enum errors error, const char *fmt, ...)
297{
298 va_list args;
299
300 va_start (args, fmt);
301 throw_verror (error, fmt, args);
302 va_end (args);
303}
304
305void
306throw_quit (const char *fmt, ...)
307{
308 va_list args;
309
310 va_start (args, fmt);
311 throw_vquit (fmt, args);
312 va_end (args);
313}
This page took 0.069784 seconds and 4 git commands to generate.