This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[commit] Add "struct exception"
- From: Andrew Cagney <cagney at gnu dot org>
- To: gdb-patches at sources dot redhat dot com
- Date: Wed, 12 Jan 2005 18:57:52 -0500
- Subject: [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 */