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