This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Make TRY/CATCH use real C++ try/catch in C++ mode


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=72df25b28d68fd0b903380ceb06c6b5866eab453

commit 72df25b28d68fd0b903380ceb06c6b5866eab453
Author: Pedro Alves <palves@redhat.com>
Date:   Sat Mar 7 14:50:03 2015 +0000

    Make TRY/CATCH use real C++ try/catch in C++ mode
    
    Although the current TRY/CATCH implementation works in C++ mode too,
    it relies on setjmp/longjmp, and longjmp bypasses calling the
    destructors of objects on the stack, which is obviously bad for C++.
    
    This patch fixes this by makes TRY/CATCH use real try/catch in C++
    mode behind the scenes.  The way this is done allows RAII and cleanups
    to coexist while we phase out cleanups, instead of requiring a flag
    day.
    
    This patch is not strictly necessary until we require a C++ compiler
    and start actually using RAII, though I'm all for baby steps, and it
    shows my proposed way forward.  Putting it in now, allows for easier
    experimentation and exposure of potential problems with real C++
    exceptions.
    
    gdb/ChangeLog:
    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.

Diff:
---
 gdb/ChangeLog                  | 27 +++++++++++++++
 gdb/common/common-exceptions.c | 77 +++++++++++++++++++++++++++++++++++++++++-
 gdb/common/common-exceptions.h | 67 ++++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8f5029a..f5da3f3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 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
 	parameter.
 
diff --git a/gdb/common/common-exceptions.c b/gdb/common/common-exceptions.c
index 2ad0ce1..b300a9d 100644
--- a/gdb/common/common-exceptions.c
+++ b/gdb/common/common-exceptions.c
@@ -22,6 +22,8 @@
 
 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.  */
@@ -185,7 +187,7 @@ exceptions_state_mc_catch (struct gdb_exception *exception,
     {
       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;
 	}
@@ -211,6 +213,56 @@ exceptions_state_mc_action_iter_1 (void)
   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
@@ -220,12 +272,31 @@ throw_exception (struct gdb_exception exception)
 
   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.
@@ -249,7 +320,11 @@ throw_it (enum return_reason reason, enum errors error, const char *fmt,
 {
   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);
 
diff --git a/gdb/common/common-exceptions.h b/gdb/common/common-exceptions.h
index d2c0bee..2e6a6d9 100644
--- a/gdb/common/common-exceptions.h
+++ b/gdb/common/common-exceptions.h
@@ -121,10 +121,16 @@ struct gdb_exception
    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.
 
@@ -151,6 +157,8 @@ extern int exceptions_state_mc_catch (struct gdb_exception *, int);
 
   */
 
+#ifndef __cplusplus
+
 #define TRY \
      { \
        SIGJMP_BUF *buf = \
@@ -168,6 +176,65 @@ extern int exceptions_state_mc_catch (struct gdb_exception *, int);
 #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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]