This is the mail archive of the gdb-patches@sources.redhat.com 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]

[commit] Add "struct exception"


If this were Java, we'd be writing:

  class ErrorException extends Exception ...;
  class NoSourceFileErrorException extends ErrorException ...;
  ...;

and then

  try {
    ...
  } catch (ErrorException e) {
    System.out.println (e.toString ());
  }

but it isn't so we can't.

The attached patch establishes a framework that makes it possible to work around this limitation of C. It adds:

	struct exception;
	struct exception catch_exception(...)
	throw_exception(struct exception)

(The existing throw_exception is renamed to throw_reason to avoid a name clash, callers updated). This lets users write a rough equivalent:

  struct exception e = catch_exceptions (....)
  switch (exception.reason)
    ...
    case ERROR_RETURN:
      print (exception.message);

and even opens the possibility of:

  TRY_CATCH (e)
    {
      ...
    }
  switch (e.reason)
    ...

The hacks error_silent and error_last_message can now be eliminated.

exceptions.[hc]'s has been rewritten to use it; tested on ppc gnu/linux.

committed,
Andrew
Index: ChangeLog
2005-01-12  Andrew Cagney  <cagney@gnu.org>

	* exceptions.h (throw_reason): Rename throw_exception.
	(enum errors, struct exception): Define.
	(catch_exception_ftype): Define.
	(catch_exception, throw_exception): Declare.
	* exceptions.c (throw_exception): Rewrite.
	(throw_reason): New function.
	(struct catcher, catcher_state_machine): Replace "reason" with
	"exception", delete "gdberrmsg".
	(catch_exception): New function.
	(catcher_init): Replace "gdberrmsg" parameter with "exception".
	(catch_errors, catch_exceptions_with_msg): Re-implement passing
	exception to catcher_init.
	* utils.c (error_silent, error_stream_1): Use throw_reason.
	(internal_verror, quit): Ditto.
	* breakpoint.c (insert_catchpoint, break_command_1): Ditto.
	* remote-fileio.c (remote_fileio_ctrl_c_signal_handler): Ditto.
	* remote.c (remote_open_1, interrupt_query): Ditto.

Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.188
diff -p -u -r1.188 breakpoint.c
--- breakpoint.c	12 Jan 2005 18:31:30 -0000	1.188
+++ breakpoint.c	12 Jan 2005 23:41:25 -0000
@@ -734,7 +734,7 @@ insert_catchpoint (struct ui_out *uo, vo
     }
 
   if (val < 0)
-    throw_exception (RETURN_ERROR);
+    throw_reason (RETURN_ERROR);
 
   return 0;
 }
@@ -5153,7 +5153,7 @@ break_command_1 (char *arg, int flag, in
 	  /* If pending breakpoint support is turned off, throw error.  */
 
 	  if (pending_break_support == AUTO_BOOLEAN_FALSE)
-	    throw_exception (RETURN_ERROR);
+	    throw_reason (RETURN_ERROR);
 
           /* If pending breakpoint support is auto query and the user selects 
 	     no, then simply return the error code.  */
Index: exceptions.c
===================================================================
RCS file: /cvs/src/src/gdb/exceptions.c,v
retrieving revision 1.2
diff -p -u -r1.2 exceptions.c
--- exceptions.c	12 Jan 2005 19:12:29 -0000	1.2
+++ exceptions.c	12 Jan 2005 23:41:25 -0000
@@ -65,17 +65,16 @@ enum catcher_action {
 struct catcher
 {
   enum catcher_state state;
-  /* Scratch variables used when transitioning a state.  */
+  /* Jump buffer pointing back at the exception handler.  */
   SIGJMP_BUF buf;
-  int reason;
-  int val;
+  /* Status buffer belonging to that exception handler.  */
+  volatile struct exception *exception;
   /* Saved/current state.  */
   int mask;
   char *saved_error_pre_print;
   char *saved_quit_pre_print;
   struct ui_out *saved_uiout;
   struct cleanup *saved_cleanup_chain;
-  char **gdberrmsg;
   /* Back link.  */
   struct catcher *prev;
 };
@@ -86,12 +85,17 @@ static struct catcher *current_catcher;
 static SIGJMP_BUF *
 catcher_init (struct ui_out *func_uiout,
 	      char *errstring,
-	      char **gdberrmsg,
+	      volatile struct exception *exception,
 	      return_mask mask)
 {
   struct catcher *new_catcher = XZALLOC (struct catcher);
 
-  new_catcher->gdberrmsg = gdberrmsg;
+  /* Start with no exception, save it's address.  */
+  exception->reason = 0;
+  exception->error = NO_ERROR;
+  exception->message = NULL;
+  new_catcher->exception = exception;
+
   new_catcher->mask = mask;
 
   /* Override error/quit messages during FUNC. */
@@ -194,14 +198,8 @@ catcher_state_machine (enum catcher_acti
 	{
 	case CATCH_ITER:
 	  {
-	    int reason = current_catcher->reason;
-	    /* If caller wants a copy of the low-level error message,
-	       make one.  This is used in the case of a silent error
-	       whereby the caller may optionally want to issue the
-	       message.  */
-	    if (current_catcher->gdberrmsg != NULL)
-	      *(current_catcher->gdberrmsg) = error_last_message ();
-	    if (current_catcher->mask & RETURN_MASK (reason))
+	    struct exception exception = *current_catcher->exception;
+	    if (current_catcher->mask & RETURN_MASK (exception.reason))
 	      {
 		/* Exit normally if this catcher can handle this
 		   exception.  The caller analyses the func return
@@ -213,7 +211,7 @@ catcher_state_machine (enum catcher_acti
 	       relay the event to the next containing
 	       catch_errors(). */
 	    catcher_pop ();
-	    throw_exception (reason);
+	    throw_exception (exception);
 	  }
 	default:
 	  internal_error (__FILE__, __LINE__, "bad state");
@@ -223,10 +221,10 @@ catcher_state_machine (enum catcher_acti
     }
 }
 
-/* Return for reason REASON to the nearest containing catch_errors().  */
+/* Return EXCEPTION to the nearest containing catch_errors().  */
 
 NORETURN void
-throw_exception (enum return_reason reason)
+throw_exception (struct exception exception)
 {
   quit_flag = 0;
   immediate_quit = 0;
@@ -243,22 +241,47 @@ throw_exception (enum return_reason reas
     do_exec_error_cleanups (ALL_CLEANUPS);
 
   if (annotation_level > 1)
-    switch (reason)
+    switch (exception.reason)
       {
       case RETURN_QUIT:
 	annotate_quit ();
 	break;
       case RETURN_ERROR:
+	/* Assume that these are all errors.  */
 	annotate_error ();
 	break;
+      default:
+	internal_error (__FILE__, __LINE__, "Bad switch.");
       }
 
   /* 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. */
   catcher_state_machine (CATCH_THROWING);
-  current_catcher->reason = reason;
-  SIGLONGJMP (current_catcher->buf, current_catcher->reason);
+  *current_catcher->exception = exception;
+  SIGLONGJMP (current_catcher->buf, exception.reason);
+}
+
+NORETURN void
+throw_reason (enum return_reason reason)
+{
+  struct exception exception;
+  memset (&exception, 0, sizeof exception);
+
+  exception.reason = reason;
+  switch (reason)
+    {
+    case RETURN_QUIT:
+      break;
+    case RETURN_ERROR:
+      exception.error = GENERIC_ERROR;
+      exception.message = error_last_message ();
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "bad switch");
+    }
+  
+  throw_exception (exception);
 }
 
 /* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any
@@ -304,6 +327,21 @@ catch_exceptions (struct ui_out *uiout,
 				    NULL, mask);
 }
 
+struct exception
+catch_exception (struct ui_out *uiout,
+		 catch_exception_ftype *func,
+		 void *func_args,
+		 return_mask mask)
+{
+  volatile struct exception exception;
+  SIGJMP_BUF *catch;
+  catch = catcher_init (uiout, NULL, &exception, mask);
+  for (SIGSETJMP ((*catch));
+       catcher_state_machine (CATCH_ITER);)
+    (*func) (uiout, func_args);
+  return exception;
+}
+
 int
 catch_exceptions_with_msg (struct ui_out *uiout,
 		  	   catch_exceptions_ftype *func,
@@ -312,17 +350,22 @@ catch_exceptions_with_msg (struct ui_out
 			   char **gdberrmsg,
 		  	   return_mask mask)
 {
-  int val = 0;
-  enum return_reason caught;
-  SIGJMP_BUF *catch;
-  catch = catcher_init (uiout, errstring, gdberrmsg, mask);
-  for (caught = SIGSETJMP ((*catch));
-       catcher_state_machine (CATCH_ITER);)
+  volatile struct exception exception;
+  volatile int val = 0;
+  SIGJMP_BUF *catch = catcher_init (uiout, errstring, &exception, mask);
+  for (SIGSETJMP ((*catch)); catcher_state_machine (CATCH_ITER);)
     val = (*func) (uiout, func_args);
   gdb_assert (val >= 0);
-  gdb_assert (caught <= 0);
-  if (caught < 0)
-    return caught;
+  gdb_assert (exception.reason <= 0);
+  if (exception.reason < 0)
+    {
+      /* If caller wants a copy of the low-level error message, make
+	 one.  This is used in the case of a silent error whereby the
+	 caller may optionally want to issue the message.  */
+      if (gdberrmsg != NULL)
+	*gdberrmsg = exception.message;
+      return exception.reason;
+    }
   return val;
 }
 
@@ -330,20 +373,15 @@ int
 catch_errors (catch_errors_ftype *func, void *func_args, char *errstring,
 	      return_mask mask)
 {
-  int val = 0;
-  enum return_reason caught;
-  SIGJMP_BUF *catch;
-  catch = catcher_init (uiout, errstring, NULL, mask);
+  volatile int val = 0;
+  volatile struct exception exception;
+  SIGJMP_BUF *catch = catcher_init (uiout, errstring, &exception, mask);
   /* This illustrates how it is possible to nest the mechanism and
      hence catch "break".  Of course this doesn't address the need to
      also catch "return".  */
-  for (caught = SIGSETJMP ((*catch)); catcher_state_machine (CATCH_ITER);)
-    for (; catcher_state_machine (CATCH_ITER_1);)
-      {
-	val = func (func_args);
-	break;
-      }
-  if (caught != 0)
+  for (SIGSETJMP ((*catch)); catcher_state_machine (CATCH_ITER);)
+    val = func (func_args);
+  if (exception.reason != 0)
     return 0;
   return val;
 }
Index: exceptions.h
===================================================================
RCS file: /cvs/src/src/gdb/exceptions.h,v
retrieving revision 1.1
diff -p -u -r1.1 exceptions.h
--- exceptions.h	12 Jan 2005 18:31:31 -0000	1.1
+++ exceptions.h	12 Jan 2005 23:41:25 -0000
@@ -24,7 +24,7 @@
 #ifndef EXCEPTIONS_H
 #define EXCEPTIONS_H
 
-/* Reasons for calling throw_exception().  NOTE: all reason values
+/* Reasons for calling throw_exceptions().  NOTE: all reason values
    must be less than zero.  enum value 0 is reserved for internal use
    as the return value from an initial setjmp().  The function
    catch_exceptions() reserves values >= 0 as legal results from its
@@ -44,17 +44,38 @@ enum return_reason
 #define RETURN_MASK_ALL		(RETURN_MASK_QUIT | RETURN_MASK_ERROR)
 typedef int return_mask;
 
-/* Throw an exception of type RETURN_REASON.  Will execute a LONG JUMP
-   to the inner most containing exception handler established using
-   catch_exceptions() (or the legacy catch_errors()).
+/* Describe all exceptions.  */
+
+enum errors {
+  NO_ERROR,
+  /* Any generic error, the corresponding text is in
+     exception.message.  */
+  GENERIC_ERROR,
+  /* Add more errors here.  */
+  NR_ERRORS
+};
+
+struct exception
+{
+  enum return_reason reason;
+  enum errors error;
+  char *message;
+};
+
+/* Throw an exception (as described by "struct exception").  Will
+   execute a LONG JUMP to the inner most containing exception handler
+   established using catch_exceptions() (or similar).
 
    Code normally throws an exception using error() et.al.  For various
    reaons, GDB also contains code that throws an exception directly.
    For instance, the remote*.c targets contain CNTRL-C signal handlers
    that propogate the QUIT event up the exception chain.  ``This could
-   be a good thing or a dangerous thing.'' -- the Existential Wombat.  */
+   be a good thing or a dangerous thing.'' -- the Existential
+   Wombat.  */
+
+extern NORETURN void throw_exception (struct exception exception) ATTR_NORETURN;
+extern NORETURN void throw_reason (enum return_reason reason) ATTR_NORETURN;
 
-extern NORETURN void throw_exception (enum return_reason) ATTR_NORETURN;
 
 /* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception
    handler.  If an exception (enum return_reason) is thrown using
@@ -87,11 +108,16 @@ typedef int (catch_exceptions_ftype) (st
 extern int catch_exceptions (struct ui_out *uiout,
 			     catch_exceptions_ftype *func, void *func_args,
 			     char *errstring, return_mask mask);
+typedef void (catch_exception_ftype) (struct ui_out *ui_out, void *args);
 extern int catch_exceptions_with_msg (struct ui_out *uiout,
 			     	      catch_exceptions_ftype *func, 
 			     	      void *func_args,
 			     	      char *errstring, char **gdberrmsg,
 				      return_mask mask);
+extern struct exception catch_exception (struct ui_out *uiout,
+					 catch_exception_ftype *func,
+					 void *func_args,
+					 return_mask mask);
 
 /* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero
    otherwize the result from CATCH_ERRORS_FTYPE is returned. It is
Index: remote-fileio.c
===================================================================
RCS file: /cvs/src/src/gdb/remote-fileio.c,v
retrieving revision 1.7
diff -p -u -r1.7 remote-fileio.c
--- remote-fileio.c	12 Jan 2005 18:31:32 -0000	1.7
+++ remote-fileio.c	12 Jan 2005 23:41:25 -0000
@@ -480,7 +480,7 @@ remote_fileio_ctrl_c_signal_handler (int
   remote_fileio_sig_set (SIG_IGN);
   remote_fio_ctrl_c_flag = 1;
   if (!remote_fio_no_longjmp)
-    throw_exception (RETURN_QUIT);
+    throw_reason (RETURN_QUIT);
   remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
 }
 
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.158
diff -p -u -r1.158 remote.c
--- remote.c	12 Jan 2005 18:31:32 -0000	1.158
+++ remote.c	12 Jan 2005 23:41:26 -0000
@@ -2257,7 +2257,7 @@ remote_open_1 (char *name, int from_tty,
       pop_target ();
       if (async_p)
 	wait_forever_enabled_p = 1;
-      throw_exception (ex);
+      throw_reason (ex);
     }
 
   if (async_p)
@@ -2723,7 +2723,7 @@ interrupt_query (void)
 Give up (and stop debugging it)? "))
     {
       target_mourn_inferior ();
-      throw_exception (RETURN_QUIT);
+      throw_reason (RETURN_QUIT);
     }
 
   target_terminal_inferior ();
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/utils.c,v
retrieving revision 1.140
diff -p -u -r1.140 utils.c
--- utils.c	12 Jan 2005 18:31:34 -0000	1.140
+++ utils.c	12 Jan 2005 23:41:26 -0000
@@ -674,7 +674,7 @@ error_silent (const char *string, ...)
   ui_file_put (tmp_stream, do_write, gdb_lasterr);
   va_end (args);
 
-  throw_exception (RETURN_ERROR);
+  throw_reason (RETURN_ERROR);
 }
 
 /* Output an error message including any pre-print text to gdb_stderr.  */
@@ -711,7 +711,7 @@ error_stream_1 (struct ui_file *stream, 
   ui_file_put (stream, do_write, gdb_stderr);
   fprintf_filtered (gdb_stderr, "\n");
 
-  throw_exception (reason);
+  throw_reason (reason);
 }
 
 NORETURN void
@@ -866,7 +866,7 @@ NORETURN void
 internal_verror (const char *file, int line, const char *fmt, va_list ap)
 {
   internal_vproblem (&internal_error_problem, file, line, fmt, ap);
-  throw_exception (RETURN_ERROR);
+  throw_reason (RETURN_ERROR);
 }
 
 NORETURN void
@@ -1007,7 +1007,7 @@ quit (void)
     fprintf_unfiltered (gdb_stderr,
 			"Quit (expect signal SIGINT when the program is resumed)\n");
 #endif
-  throw_exception (RETURN_QUIT);
+  throw_reason (RETURN_QUIT);
 }
 
 /* Control C comes here */

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