Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 36/36] Make TRY/CATCH use real C++ try/catch in C++ mode
Date: Mon, 09 Feb 2015 23:22:00 -0000	[thread overview]
Message-ID: <1423524046-20605-37-git-send-email-palves@redhat.com> (raw)
In-Reply-To: <1423524046-20605-1-git-send-email-palves@redhat.com>

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.  I think we should put it in now, to
allow easier experimentation and exposure of potential problems with
real C++ exceptions.

gdb/ChangeLog:
2015-02-09  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.
---
 gdb/common/common-exceptions.c | 77 +++++++++++++++++++++++++++++++++++++++++-
 gdb/common/common-exceptions.h | 67 ++++++++++++++++++++++++++++++++++++
 2 files changed, 143 insertions(+), 1 deletion(-)

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
-- 
1.9.3


  parent reply	other threads:[~2015-02-09 23:22 UTC|newest]

Thread overview: 100+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-09 23:20 [PATCH 00/36] Support building GDB as a C++ program Pedro Alves
2015-02-09 23:20 ` [PATCH 02/36] Add --enable-build-with-cxx configure switch Pedro Alves
2015-02-10 22:11   ` Yao Qi
2015-02-27 13:24     ` Pedro Alves
2015-02-27 14:20       ` Yao Qi
2015-02-27 16:29         ` Pedro Alves
2015-02-09 23:21 ` [PATCH 11/36] Make functions and variables exported by the IPA be extern "C" Pedro Alves
2015-02-09 23:21 ` [PATCH 17/36] mi/mi-cmd-stack.c|frame filters: print_values <-> ext_lang_frame_args Pedro Alves
2015-02-09 23:21 ` [PATCH 25/36] python/python-internal.h: enum ‘ext_lang_rc’ not defined Pedro Alves
2015-02-09 23:21 ` [PATCH 28/36] Move exception_none to common code, and use it Pedro Alves
2015-02-09 23:21 ` [PATCH 19/36] Exported const objects Pedro Alves
2015-02-09 23:21 ` [PATCH 16/36] x86 Linux/ptrace: fix offsetof usage in C++ mode Pedro Alves
2015-02-09 23:21 ` [PATCH 03/36] C++ keyword cleanliness, mostly auto-generated Pedro Alves
2015-02-11  7:57   ` Joel Brobecker
2015-02-11  8:52     ` Phil Muldoon
2015-02-11 10:27     ` Pedro Alves
2015-02-11 10:51       ` Pedro Alves
2015-02-12 12:19         ` Joel Brobecker
2015-02-12 13:14           ` Pedro Alves
2015-02-12 14:43             ` Pedro Alves
2015-02-12 14:59               ` Joel Brobecker
2015-02-27 17:41         ` Pedro Alves
2015-02-09 23:21 ` [PATCH 26/36] Adjust self tests to cope with GDB built as a C++ program Pedro Alves
2015-02-09 23:21 ` [PATCH 04/36] Fix struct, union, and enum nesting in C++ Pedro Alves
2015-02-09 23:21 ` [PATCH 27/36] catch_command_errors: Remove 'mask' parameter Pedro Alves
2015-02-09 23:21 ` [PATCH 29/36] Normalize TRY_CATCH exception handling block Pedro Alves
2015-02-09 23:21 ` [PATCH 21/36] opcodes/microblaze: Rename 'or', 'and', 'xor' to avoid C++ conflict Pedro Alves
2015-02-10 15:05   ` Michael Eager
2015-02-10 18:11     ` Pedro Alves
2015-02-09 23:21 ` [PATCH 13/36] target.h: Include infrun.h Pedro Alves
2015-02-09 23:21 ` [PATCH 20/36] gdbserver/tracepoint: Add cast sockaddr_un/sockaddr cast Pedro Alves
2015-02-09 23:21 ` [PATCH 08/36] elf-bfd.h: Wrap in extern "C" Pedro Alves
2015-02-09 23:33   ` Andrew Pinski
2015-02-10 12:05     ` [PATCH v2] Wrap BFD headers " Pedro Alves
2015-02-11  0:36       ` Alan Modra
2015-02-11 10:08         ` Pedro Alves
2015-02-09 23:21 ` [PATCH 09/36] floatformat.h: Wrap " Pedro Alves
2015-02-09 23:35   ` Andrew Pinski
2015-02-09 23:49     ` Pedro Alves
2015-02-12 11:49       ` Pedro Alves
2015-02-18 19:55         ` Jakub Jelinek
2015-02-14 17:29       ` Doug Evans
2015-02-14 18:36         ` Pedro Alves
2015-02-14 22:46           ` Doug Evans
2015-02-09 23:21 ` [PATCH 05/36] Fix redefinition errors in C++ mode Pedro Alves
2015-02-11 10:09   ` Yao Qi
2015-02-11 11:30     ` Pedro Alves
2015-02-11 11:39       ` [PATCH] xcoffread.c: delete 'within_function' definition (Re: [PATCH 05/36] Fix redefinition errors in C++ mode) Pedro Alves
2015-02-09 23:21 ` [PATCH 12/36] proc-service, extern "C" Pedro Alves
2015-02-09 23:21 ` [PATCH 31/36] Split TRY_CATCH into TRY + CATCH Pedro Alves
2015-03-07 15:58   ` Pedro Alves
2015-02-09 23:21 ` [PATCH 15/36] Don't forward declare enum target_hw_bp_type Pedro Alves
2015-02-09 23:21 ` [PATCH 23/36] gdbarch.h: include regcache.h Pedro Alves
2015-02-09 23:21 ` [PATCH 22/36] Remove duplicate const Pedro Alves
2015-02-09 23:22 ` [PATCH 32/36] TRY_CATCH -> TRY+CATCH+END_CATCH everywhere Pedro Alves
2015-02-09 23:22 ` Pedro Alves [this message]
2015-02-09 23:22 ` [PATCH 33/36] TRY_CATCH -> TRY+CATCH+END_CATCH, the manual conversions Pedro Alves
2015-02-09 23:35 ` [PATCH 18/36] Rename struct lzma_stream to avoid clash with system header Pedro Alves
2015-02-09 23:45 ` [PATCH 06/36] record-btrace.c: Remove redefinitions Pedro Alves
2015-02-09 23:46 ` [PATCH 35/36] kill volatile struct gdb_exception Pedro Alves
2015-02-09 23:49 ` [PATCH 00/36] Support building GDB as a C++ program Doug Evans
2015-02-09 23:50 ` [PATCH 34/36] more making TRY/CATCH callers look more like real C++ try/catch blocks Pedro Alves
2015-03-07 15:59   ` Pedro Alves
2015-02-09 23:51 ` [PATCH 07/36] Make array object extern Pedro Alves
2015-02-27 22:47   ` Simon Marchi
2015-02-27 22:58     ` Pedro Alves
2015-02-27 23:04       ` Simon Marchi
2015-02-09 23:51 ` [PATCH 14/36] Do not do arithmetic on enum types Pedro Alves
2015-02-09 23:53 ` [PATCH 01/36] Create libiberty/libiberty.m4, have GDB and GDBserver use it Pedro Alves
2015-02-09 23:35   ` Pedro Alves
2015-02-27 16:23   ` Pedro Alves
2015-02-09 23:54 ` [PATCH 30/36] quit_force: Replace TRY_CATCH wrapper macros Pedro Alves
2015-02-09 23:54 ` [PATCH 10/36] Add extern "C" to declarations of C symbols Pedro Alves
2015-02-11 11:51   ` Pedro Alves
2015-02-10  0:21 ` [PATCH 24/36] breakpoint.h: move enum ‘print_stop_action’ Pedro Alves
2015-02-11 12:28   ` Yao Qi
2015-02-10 15:07 ` [PATCH 00/36] Support building GDB as a C++ program Michael Eager
2015-02-11 17:15 ` Yao Qi
2015-02-12 11:34   ` Pedro Alves
2015-02-17 23:19 ` Patrick Palka
2015-02-18 21:54   ` Yao Qi
2015-02-18 23:49     ` Patrick Palka
2015-02-27 18:19 ` Pedro Alves
2015-02-27 23:52   ` Patrick Palka
2015-02-28  0:09     ` Pedro Alves
2015-03-07 16:01   ` Pedro Alves
2015-03-07 17:58     ` [all pushed] " Pedro Alves
2015-03-16  4:42       ` asmwarrior
2015-03-16  5:05         ` asmwarrior
2015-03-16  5:22           ` asmwarrior
2015-03-16  7:15             ` asmwarrior
2015-03-16  8:20               ` asmwarrior
2015-03-16 11:43                 ` [pushed] stub-termcap.c: prototype tputs's parameter's parameter, for C++ mode (Re: [all pushed] Re: [PATCH 00/36] Support building GDB as a C++ program) Pedro Alves
2015-03-16 11:46                 ` [pushed] stub termcap, add extern "C" " Pedro Alves
2015-03-16 11:55                 ` [all pushed] Re: [PATCH 00/36] Support building GDB as a C++ program Pedro Alves
2015-03-16 11:42           ` Pedro Alves
2015-05-15  8:13             ` asmwarrior
2015-05-15  8:24               ` asmwarrior
2015-05-15 15:09                 ` Pedro Alves
2015-05-15 15:04               ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1423524046-20605-37-git-send-email-palves@redhat.com \
    --to=palves@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox