GDBserver
common-exceptions.c
Go to the documentation of this file.
1 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2 
3  Copyright (C) 1986-2015 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 = { 0, GDB_NO_ERROR, NULL };
24 
25 #ifndef __cplusplus
26 
27 /* Possible catcher states. */
29  /* Initial state, a new catcher has just been created. */
31  /* The catch code is running. */
34  /* The catch code threw an exception. */
36 };
37 
38 /* Possible catcher actions. */
43 };
44 
45 struct catcher
46 {
48  /* Jump buffer pointing back at the exception handler. */
50  /* Status buffer belonging to the exception handler. */
53  /* Back link. */
54  struct catcher *prev;
55 };
56 
57 /* Where to go for throw_exception(). */
58 static struct catcher *current_catcher;
59 
60 /* Return length of current_catcher list. */
61 
62 static int
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 SIGJMP_BUF *
78 {
79  struct catcher *new_catcher = XCNEW (struct catcher);
80 
81  /* Start with no exception. */
82  new_catcher->exception = exception_none;
83 
84  /* Prevent error/quit during FUNC from calling cleanups established
85  prior to here. */
86  new_catcher->saved_cleanup_chain = save_cleanups ();
87 
88  /* Push this new catcher on the top. */
89  new_catcher->prev = current_catcher;
90  current_catcher = new_catcher;
91  new_catcher->state = CATCHER_CREATED;
92 
93  return &new_catcher->buf;
94 }
95 
96 static void
98 {
99  struct catcher *old_catcher = current_catcher;
100 
101  current_catcher = old_catcher->prev;
102 
103  /* Restore the cleanup chain, the error/quit messages, and the uiout
104  builder, to their original states. */
105 
106  restore_cleanups (old_catcher->saved_cleanup_chain);
107 
108  xfree (old_catcher);
109 }
110 
111 /* Catcher state machine. Returns non-zero if the m/c should be run
112  again, zero if it should abort. */
113 
114 static int
116 {
117  switch (current_catcher->state)
118  {
119  case CATCHER_CREATED:
120  switch (action)
121  {
122  case CATCH_ITER:
123  /* Allow the code to run the catcher. */
124  current_catcher->state = CATCHER_RUNNING;
125  return 1;
126  default:
127  internal_error (__FILE__, __LINE__, _("bad state"));
128  }
129  case CATCHER_RUNNING:
130  switch (action)
131  {
132  case CATCH_ITER:
133  /* No error/quit has occured. */
134  return 0;
135  case CATCH_ITER_1:
136  current_catcher->state = CATCHER_RUNNING_1;
137  return 1;
138  case CATCH_THROWING:
139  current_catcher->state = CATCHER_ABORTING;
140  /* See also throw_exception. */
141  return 1;
142  default:
143  internal_error (__FILE__, __LINE__, _("bad switch"));
144  }
145  case CATCHER_RUNNING_1:
146  switch (action)
147  {
148  case CATCH_ITER:
149  /* The did a "break" from the inner while loop. */
150  return 0;
151  case CATCH_ITER_1:
152  current_catcher->state = CATCHER_RUNNING;
153  return 0;
154  case CATCH_THROWING:
155  current_catcher->state = CATCHER_ABORTING;
156  /* See also throw_exception. */
157  return 1;
158  default:
159  internal_error (__FILE__, __LINE__, _("bad switch"));
160  }
161  case CATCHER_ABORTING:
162  switch (action)
163  {
164  case CATCH_ITER:
165  {
166  /* Exit normally if this catcher can handle this
167  exception. The caller analyses the func return
168  values. */
169  return 0;
170  }
171  default:
172  internal_error (__FILE__, __LINE__, _("bad state"));
173  }
174  default:
175  internal_error (__FILE__, __LINE__, _("bad switch"));
176  }
177 }
178 
179 int
181  int mask)
182 {
183  *exception = current_catcher->exception;
184  catcher_pop ();
185 
186  if (exception->reason < 0)
187  {
188  if (mask & RETURN_MASK (exception->reason))
189  {
190  /* Exit normally and let the caller handle the
191  exception. */
192  return 1;
193  }
194 
195  /* The caller didn't request that the event be caught, relay the
196  event to the next exception_catch/CATCH. */
197  throw_exception (*exception);
198  }
199 
200  /* No exception was thrown. */
201  return 0;
202 }
203 
204 int
206 {
208 }
209 
210 int
212 {
214 }
215 
216 #else /* !__cplusplus */
217 
218 /* How many nested TRY blocks we have. See exception_messages and
219  throw_it. */
220 
221 static int try_scope_depth;
222 
223 /* Called on entry to a TRY scope. */
224 
225 void *
226 exception_try_scope_entry (void)
227 {
228  ++try_scope_depth;
229  return (void *) save_cleanups ();
230 }
231 
232 /* Called on exit of a TRY scope, either normal exit or exception
233  exit. */
234 
235 void
236 exception_try_scope_exit (void *saved_state)
237 {
238  restore_cleanups ((struct cleanup *) saved_state);
239  --try_scope_depth;
240 }
241 
242 /* Called by the default catch block. IOW, we'll get here before
243  jumping out to the next outermost scope an exception if a GDB
244  exception is not caught. */
245 
246 void
247 exception_rethrow (void)
248 {
249  /* Run this scope's cleanups before re-throwing to the next
250  outermost scope. */
253  throw;
254 }
255 
256 /* Copy the 'gdb_exception' portion of FROM to TO. */
257 
258 static void
259 gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
260 {
261  *to = *from;
262 }
263 
264 #endif /* !__cplusplus */
265 
266 /* Return EXCEPTION to the nearest containing catch_errors(). */
267 
268 void
270 {
272 
274 
275 #ifndef __cplusplus
276  /* Jump to the containing catch_errors() call, communicating REASON
277  to that call via setjmp's return value. Note that REASON can't
278  be zero, by definition in defs.h. */
280  current_catcher->exception = exception;
281  SIGLONGJMP (current_catcher->buf, exception.reason);
282 #else
283  if (exception.reason == RETURN_QUIT)
284  {
285  gdb_exception_RETURN_MASK_QUIT ex;
286 
287  gdb_exception_sliced_copy (&ex, &exception);
288  throw ex;
289  }
290  else if (exception.reason == RETURN_ERROR)
291  {
292  gdb_exception_RETURN_MASK_ERROR ex;
293 
294  gdb_exception_sliced_copy (&ex, &exception);
295  throw ex;
296  }
297  else
298  gdb_assert_not_reached ("invalid return reason");
299 #endif
300 }
301 
302 /* A stack of exception messages.
303  This is needed to handle nested calls to throw_it: we don't want to
304  xfree space for a message before it's used.
305  This can happen if we throw an exception during a cleanup:
306  An outer TRY_CATCH may have an exception message it wants to print,
307  but while doing cleanups further calls to throw_it are made.
308 
309  This is indexed by the size of the current_catcher list.
310  It is a dynamically allocated array so that we don't care how deeply
311  GDB nests its TRY_CATCHs. */
312 static char **exception_messages;
313 
314 /* The number of currently allocated entries in exception_messages. */
316 
317 static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
318 throw_it (enum return_reason reason, enum errors error, const char *fmt,
319  va_list ap)
320 {
321  struct gdb_exception e;
322  char *new_message;
323 #ifndef __cplusplus
324  int depth = catcher_list_size ();
325 #else
326  int depth = try_scope_depth;
327 #endif
328 
329  gdb_assert (depth > 0);
330 
331  /* Note: The new message may use an old message's text. */
332  new_message = xstrvprintf (fmt, ap);
333 
334  if (depth > exception_messages_size)
335  {
336  int old_size = exception_messages_size;
337 
338  exception_messages_size = depth + 10;
339  exception_messages = (char **) xrealloc (exception_messages,
340  exception_messages_size
341  * sizeof (char *));
342  memset (exception_messages + old_size, 0,
343  (exception_messages_size - old_size) * sizeof (char *));
344  }
345 
346  xfree (exception_messages[depth - 1]);
347  exception_messages[depth - 1] = new_message;
348 
349  /* Create the exception. */
350  e.reason = reason;
351  e.error = error;
352  e.message = new_message;
353 
354  /* Throw the exception. */
355  throw_exception (e);
356 }
357 
358 void
359 throw_verror (enum errors error, const char *fmt, va_list ap)
360 {
361  throw_it (RETURN_ERROR, error, fmt, ap);
362 }
363 
364 void
365 throw_vquit (const char *fmt, va_list ap)
366 {
367  throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
368 }
369 
370 void
371 throw_error (enum errors error, const char *fmt, ...)
372 {
373  va_list args;
374 
375  va_start (args, fmt);
376  throw_verror (error, fmt, args);
377  va_end (args);
378 }
379 
380 void
381 throw_quit (const char *fmt, ...)
382 {
383  va_list args;
384 
385  va_start (args, fmt);
386  throw_vquit (fmt, args);
387  va_end (args);
388 }
static int catcher_list_size(void)
return_reason
char * xstrvprintf(const char *format, va_list ap)
Definition: common-utils.c:119
SIGJMP_BUF * exceptions_state_mc_init(void)
#define RETURN_MASK(reason)
int exceptions_state_mc_action_iter(void)
enum errors error
void internal_error(const char *file, int line, const char *fmt,...)
Definition: errors.c:50
const struct gdb_exception exception_none
void restore_cleanups(struct cleanup *chain)
Definition: cleanups.c:274
static int exceptions_state_mc(enum catcher_action action)
#define _(String)
Definition: gdb_locale.h:40
struct gdb_exception exception
struct cleanup * all_cleanups(void)
Definition: cleanups.c:166
SIGJMP_BUF buf
struct cleanup * save_cleanups(void)
Definition: cleanups.c:243
#define SIGLONGJMP(buf, val)
Definition: gdb_setjmp.h:31
static void catcher_pop(void)
#define gdb_assert_not_reached(message)
Definition: gdb_assert.h:56
int exceptions_state_mc_action_iter_1(void)
static struct catcher * current_catcher
#define gdb_assert(expr)
Definition: gdb_assert.h:33
void prepare_to_throw_exception(void)
Definition: utils.c:144
static int exception_messages_size
int exceptions_state_mc_catch(struct gdb_exception *exception, int mask)
#define SIGJMP_BUF
Definition: gdb_setjmp.h:29
PTR xrealloc(PTR ptr, size_t size)
Definition: common-utils.c:51
void throw_exception(struct gdb_exception exception)
void xfree(void *ptr)
Definition: common-utils.c:97
static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF(3, 0)
void throw_verror(enum errors error, const char *fmt, va_list ap)
void throw_vquit(const char *fmt, va_list ap)
struct cleanup * saved_cleanup_chain
static char ** exception_messages
catcher_action
void throw_quit(const char *fmt,...)
const char * message
struct catcher * prev
enum catcher_state state
catcher_state
void error(const char *fmt,...)
Definition: errors.c:38
void throw_error(enum errors error, const char *fmt,...)
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:175
enum return_reason reason