+2015-03-07 Pedro Alves <palves@redhat.com>
+
+ * common/common-exceptions.c [!__cplusplus] (enum catcher_state)
+ (exceptions_state_mc_action_iter)
+ (exceptions_state_mc_action_iter_1, exceptions_state_mc_catch):
+ Don't define.
+ [__cplusplus] (try_scope_depth): New global.
+ [__cplusplus] (exception_try_scope_entry)
+ (exception_try_scope_exit, gdb_exception_sliced_copy)
+ (exception_rethrow): New functions.
+ (throw_exception): In C++ mode, throw
+ gdb_exception_RETURN_MASK_QUIT for RETURN_QUIT and
+ gdb_exception_RETURN_MASK_ERROR for RETURN_ERROR.
+ (throw_it): In C++ mode, use try_scope_depth.
+ * common/common-exceptions.h [!__cplusplus]
+ (exceptions_state_mc_action_iter)
+ (exceptions_state_mc_action_iter_1, exceptions_state_mc_catch):
+ Don't declare.
+ [__cplusplus] (exception_try_scope_entry)
+ (exception_try_scope_exit, exception_rethrow): Declare.
+ [__cplusplus] (struct exception_try_scope): New struct.
+ [__cplusplus] (TRY, CATCH, END_CATCH): Reimplement on top of real
+ C++ exceptions.
+ (struct gdb_exception_RETURN_MASK_ALL)
+ (struct gdb_exception_RETURN_MASK_ERROR)
+ (struct gdb_exception_RETURN_MASK_QUIT): New types.
+
2015-03-07 Pedro Alves <palves@redhat.com>
* main.c (handle_command_errors): Remove volatile qualifier from
const struct gdb_exception exception_none = { 0, GDB_NO_ERROR, NULL };
+#ifndef __cplusplus
+
/* Possible catcher states. */
enum catcher_state {
/* Initial state, a new catcher has just been created. */
{
if (mask & RETURN_MASK (exception->reason))
{
- /* Exit normally and let the called handle the
+ /* Exit normally and let the caller handle the
exception. */
return 1;
}
return exceptions_state_mc (CATCH_ITER_1);
}
+#else /* !__cplusplus */
+
+/* How many nested TRY blocks we have. See exception_messages and
+ throw_it. */
+
+static int try_scope_depth;
+
+/* Called on entry to a TRY scope. */
+
+void *
+exception_try_scope_entry (void)
+{
+ ++try_scope_depth;
+ return (void *) save_cleanups ();
+}
+
+/* Called on exit of a TRY scope, either normal exit or exception
+ exit. */
+
+void
+exception_try_scope_exit (void *saved_state)
+{
+ restore_cleanups ((struct cleanup *) saved_state);
+ --try_scope_depth;
+}
+
+/* Called by the default catch block. IOW, we'll get here before
+ jumping out to the next outermost scope an exception if a GDB
+ exception is not caught. */
+
+void
+exception_rethrow (void)
+{
+ /* Run this scope's cleanups before re-throwing to the next
+ outermost scope. */
+ prepare_to_throw_exception ();
+ do_cleanups (all_cleanups ());
+ throw;
+}
+
+/* Copy the 'gdb_exception' portion of FROM to TO. */
+
+static void
+gdb_exception_sliced_copy (struct gdb_exception *to, const struct gdb_exception *from)
+{
+ *to = *from;
+}
+
+#endif /* !__cplusplus */
+
/* Return EXCEPTION to the nearest containing catch_errors(). */
void
do_cleanups (all_cleanups ());
+#ifndef __cplusplus
/* Jump to the containing catch_errors() call, communicating REASON
to that call via setjmp's return value. Note that REASON can't
be zero, by definition in defs.h. */
exceptions_state_mc (CATCH_THROWING);
current_catcher->exception = exception;
SIGLONGJMP (current_catcher->buf, exception.reason);
+#else
+ if (exception.reason == RETURN_QUIT)
+ {
+ gdb_exception_RETURN_MASK_QUIT ex;
+
+ gdb_exception_sliced_copy (&ex, &exception);
+ throw ex;
+ }
+ else if (exception.reason == RETURN_ERROR)
+ {
+ gdb_exception_RETURN_MASK_ERROR ex;
+
+ gdb_exception_sliced_copy (&ex, &exception);
+ throw ex;
+ }
+ else
+ gdb_assert_not_reached ("invalid return reason");
+#endif
}
/* A stack of exception messages.
{
struct gdb_exception e;
char *new_message;
+#ifndef __cplusplus
int depth = catcher_list_size ();
+#else
+ int depth = try_scope_depth;
+#endif
gdb_assert (depth > 0);
the exceptions subsystem and not used other than via the TRY/CATCH
macros defined below. */
+#ifndef __cplusplus
extern SIGJMP_BUF *exceptions_state_mc_init (void);
extern int exceptions_state_mc_action_iter (void);
extern int exceptions_state_mc_action_iter_1 (void);
extern int exceptions_state_mc_catch (struct gdb_exception *, int);
+#else
+extern void *exception_try_scope_entry (void);
+extern void exception_try_scope_exit (void *saved_state);
+extern void exception_rethrow (void);
+#endif
/* Macro to wrap up standard try/catch behavior.
*/
+#ifndef __cplusplus
+
#define TRY \
{ \
SIGJMP_BUF *buf = \
#define END_CATCH \
}
+#else
+
+/* Prevent error/quit during TRY from calling cleanups established
+ prior to here. This pops out the scope in either case of normal
+ exit or exception exit. */
+struct exception_try_scope
+{
+ exception_try_scope ()
+ {
+ saved_state = exception_try_scope_entry ();
+ }
+ ~exception_try_scope ()
+ {
+ exception_try_scope_exit (saved_state);
+ }
+
+ void *saved_state;
+};
+
+/* We still need to wrap TRY/CATCH in C++ so that cleanups and C++
+ exceptions can coexist. The TRY blocked is wrapped in a
+ do/while(0) so that break/continue within the block works the same
+ as in C. */
+#define TRY \
+ try \
+ { \
+ exception_try_scope exception_try_scope_instance; \
+ do \
+ {
+
+#define CATCH(EXCEPTION, MASK) \
+ } while (0); \
+ } \
+ catch (struct gdb_exception ## _ ## MASK &EXCEPTION)
+
+#define END_CATCH \
+ catch (...) \
+ { \
+ exception_rethrow (); \
+ }
+
+/* The exception types client code may catch. They're just shims
+ around gdb_exception that add nothing but type info. Which is used
+ is selected depending on the MASK argument passed to CATCH. */
+
+struct gdb_exception_RETURN_MASK_ALL : public gdb_exception
+{
+};
+
+struct gdb_exception_RETURN_MASK_ERROR : public gdb_exception_RETURN_MASK_ALL
+{
+};
+
+struct gdb_exception_RETURN_MASK_QUIT : public gdb_exception_RETURN_MASK_ALL
+{
+};
+
+#endif
+
/* *INDENT-ON* */
/* Hook to allow client-specific actions to be performed prior to