This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[rfa] catch_exceptions()
- To: gdb-patches at sources dot redhat dot com
- Subject: [rfa] catch_exceptions()
- From: Andrew Cagney <ac131313 at cygnus dot com>
- Date: Wed, 15 Aug 2001 20:55:42 -0400
Hello,
Following up on my last e-mail, here is a tested patch that adds
catch_exceptions() to top.c
If this is approved, I think I'll add catch_errors() to the ARI (under
warnings).
Andrew
2001-08-13 Andrew Cagney <ac131313@redhat.com>
* defs.h (enum return_reason): Renumber so that all values are
negative.
(RETURN_MASK): Negate reason.
(catch_exception_ftype): Declare.
(catch_exceptions): Declare.
* top.c (catcher): New function, based on catch_errors. Add in
parameter func_uiout and out parameters func_val, func_caught and
func_cleanup. Change type of func to catch_exceptions_ftype.
Save/restore uiout.
(struct catch_errors_args): Define.
(do_catch_errors): New function.
(catch_errors): Rewrite, use do_catch_errors and catcher.
(catch_exceptions): New function, use catcher.
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.62
diff -p -r1.62 defs.h
*** defs.h 2001/08/02 20:57:19 1.62
--- defs.h 2001/08/15 17:49:33
*************** extern NORETURN void internal_error (con
*** 1084,1104 ****
extern NORETURN void nomem (long) ATTR_NORETURN;
! /* Reasons for calling return_to_top_level. Note: enum value 0 is
! reserved for internal use as the return value from an initial
! setjmp(). */
enum return_reason
{
/* User interrupt. */
! RETURN_QUIT = 1,
/* Any other error. */
RETURN_ERROR
};
#define ALL_CLEANUPS ((struct cleanup *)0)
! #define RETURN_MASK(reason) (1 << (int)(reason))
#define RETURN_MASK_QUIT RETURN_MASK (RETURN_QUIT)
#define RETURN_MASK_ERROR RETURN_MASK (RETURN_ERROR)
#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
--- 1084,1106 ----
extern NORETURN void nomem (long) ATTR_NORETURN;
! /* Reasons for calling return_to_top_level. 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 functioin
! catch_exceptions() reserves values >= 0 as legal results from its
! wrapped function. */
enum return_reason
{
/* User interrupt. */
! RETURN_QUIT = -2,
/* Any other error. */
RETURN_ERROR
};
#define ALL_CLEANUPS ((struct cleanup *)0)
! #define RETURN_MASK(reason) (1 << (int)(-reason))
#define RETURN_MASK_QUIT RETURN_MASK (RETURN_QUIT)
#define RETURN_MASK_ERROR RETURN_MASK (RETURN_ERROR)
#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
*************** typedef int return_mask;
*** 1106,1117 ****
extern NORETURN void return_to_top_level (enum return_reason) ATTR_NORETURN;
/* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero
otherwize the result from CATCH_ERRORS_FTYPE is returned. It is
probably useful for CATCH_ERRORS_FTYPE to always return a non-zero
value. It's unfortunate that, catch_errors() does not return an
indication of the exact exception that it caught - quit_flag might
! help. */
typedef int (catch_errors_ftype) (PTR);
extern int catch_errors (catch_errors_ftype *, PTR, char *, return_mask);
--- 1108,1148 ----
extern NORETURN void return_to_top_level (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
+ return_to_top_level() than all cleanups installed since
+ catch_exceptions() was entered are invoked, the (-ve) exception
+ value is then returned by catch_exceptions. If FUNC() returns
+ normally (with a postive or zero return value) then that value is
+ returned by catch_exceptions(). It is an internal_error() for
+ FUNC() to return a negative value.
+
+ For the period of the FUNC() call: UIOUT is installed as the output
+ builder; ERRSTRING is installed as the error/quit message; and a
+ new cleanup_chain is established. The old values are restored
+ before catch_exceptions() returns.
+
+ FIXME; cagney/2001-08-13: The need to override the global UIOUT
+ builder variable should just go away.
+
+ This function superseeds catch_errors().
+
+ This function uses SETJMP() and LONGJUMP(). */
+
+ struct ui_out;
+ typedef int (catch_exceptions_ftype) (struct ui_out *ui_out, void *args);
+ extern int catch_exceptions (struct ui_out *uiout,
+ catch_exceptions_ftype *func, void *func_args,
+ char *errstring, 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
probably useful for CATCH_ERRORS_FTYPE to always return a non-zero
value. It's unfortunate that, catch_errors() does not return an
indication of the exact exception that it caught - quit_flag might
! help.
!
! This function is superseeded by catch_exceptions(). */
typedef int (catch_errors_ftype) (PTR);
extern int catch_errors (catch_errors_ftype *, PTR, char *, return_mask);
Index: top.c
===================================================================
RCS file: /cvs/src/src/gdb/top.c,v
retrieving revision 1.42
diff -p -r1.42 top.c
*** top.c 2001/08/01 18:39:23 1.42
--- top.c 2001/08/15 17:49:40
***************
*** 41,46 ****
--- 41,47 ----
#include "version.h"
#include "serial.h"
#include "doublest.h"
+ #include "gdb_assert.h"
/* readline include files */
#include <readline/readline.h>
*************** return_to_top_level (enum return_reason
*** 347,356 ****
(NORETURN void) SIGLONGJMP (*catch_return, (int) reason);
}
! /* Call FUNC with arg ARGS, catching any errors. If there is no
! error, return the value returned by FUNC. If there is an error,
! print ERRSTRING, print the specific error message, then return
! zero.
Must not be called with immediate_quit in effect (bad things might
happen, say we got a signal in the middle of a memcpy to quit_return).
--- 348,358 ----
(NORETURN void) SIGLONGJMP (*catch_return, (int) reason);
}
! /* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any
! errors. Set FUNC_CAUGHT to an ``enum return_reason'' if the
! function is aborted (using return_to_top_level() or zero if the
! function returns normally. Set FUNC_VAL to the value returned by
! the function or 0 if the function was aborted.
Must not be called with immediate_quit in effect (bad things might
happen, say we got a signal in the middle of a memcpy to quit_return).
*************** return_to_top_level (enum return_reason
*** 378,398 ****
be consolidated into a single file instead of being distributed
between utils.c and top.c? */
! int
! catch_errors (catch_errors_ftype *func, void * args, char *errstring,
! return_mask mask)
{
SIGJMP_BUF *saved_catch;
SIGJMP_BUF catch;
- int val;
struct cleanup *saved_cleanup_chain;
char *saved_error_pre_print;
char *saved_quit_pre_print;
/* Return value from SIGSETJMP(): enum return_reason if error or
quit caught, 0 otherwise. */
int caught;
/* Override error/quit messages during FUNC. */
saved_error_pre_print = error_pre_print;
--- 380,409 ----
be consolidated into a single file instead of being distributed
between utils.c and top.c? */
! static void
! catcher (catch_exceptions_ftype *func,
! struct ui_out *func_uiout,
! void *func_args,
! int *func_val,
! enum return_reason *func_caught,
! char *errstring,
! return_mask mask)
{
SIGJMP_BUF *saved_catch;
SIGJMP_BUF catch;
struct cleanup *saved_cleanup_chain;
char *saved_error_pre_print;
char *saved_quit_pre_print;
+ struct ui_out *saved_uiout;
/* Return value from SIGSETJMP(): enum return_reason if error or
quit caught, 0 otherwise. */
int caught;
+ /* Return value from FUNC(): Hopefully non-zero. Explicitly set to
+ zero if an error quit was caught. */
+ int val;
+
/* Override error/quit messages during FUNC. */
saved_error_pre_print = error_pre_print;
*************** catch_errors (catch_errors_ftype *func,
*** 403,408 ****
--- 414,424 ----
if (mask & RETURN_MASK_QUIT)
quit_pre_print = errstring;
+ /* Override the global ``struct ui_out'' builder. */
+
+ saved_uiout = uiout;
+ uiout = func_uiout;
+
/* Prevent error/quit during FUNC from calling cleanups established
prior to here. */
*************** catch_errors (catch_errors_ftype *func,
*** 414,420 ****
catch_return = &catch;
caught = SIGSETJMP (catch);
if (!caught)
! val = (*func) (args);
else
val = 0;
catch_return = saved_catch;
--- 430,436 ----
catch_return = &catch;
caught = SIGSETJMP (catch);
if (!caught)
! val = (*func) (func_uiout, func_args);
else
val = 0;
catch_return = saved_catch;
*************** catch_errors (catch_errors_ftype *func,
*** 426,472 ****
do_cleanups call (to cover the problem) or an assertion check to
detect bad FUNCs code. */
! /* Restore the cleanup chain and error/quit messages to their
! original states. */
restore_cleanups (saved_cleanup_chain);
if (mask & RETURN_MASK_QUIT)
quit_pre_print = saved_quit_pre_print;
if (mask & RETURN_MASK_ERROR)
error_pre_print = saved_error_pre_print;
-
- /* Return normally if no error/quit event occurred. */
! if (!caught)
! return val;
! /* If the caller didn't request that the event be caught, relay the
event to the next containing catch_errors(). */
! if (!(mask & RETURN_MASK (caught)))
! return_to_top_level (caught);
!
! /* Tell the caller that an event was caught.
!
! FIXME: nsd/2000-02-22: When MASK is RETURN_MASK_ALL, the caller
! can't tell what type of event occurred.
! A possible fix is to add a new interface, catch_event(), that
! returns enum return_reason after catching an error or a quit.
! When returning normally, i.e. without catching an error or a
! quit, catch_event() could return RETURN_NORMAL, which would be
! added to enum return_reason. FUNC would return information
! exclusively via ARGS.
! Alternatively, normal catch_event() could return FUNC's return
! value. The caller would need to be aware of potential overlap
! with enum return_reason, which could be publicly restricted to
! negative values to simplify return value processing in FUNC and
! in the caller. */
! return 0;
}
struct captured_command_args
--- 442,519 ----
do_cleanups call (to cover the problem) or an assertion check to
detect bad FUNCs code. */
! /* Restore the cleanup chain, the error/quit messages, and the uiout
! builder, to their original states. */
restore_cleanups (saved_cleanup_chain);
+ uiout = saved_uiout;
+
if (mask & RETURN_MASK_QUIT)
quit_pre_print = saved_quit_pre_print;
if (mask & RETURN_MASK_ERROR)
error_pre_print = saved_error_pre_print;
! /* Return normally if no error/quit event occurred or this catcher
! can handle this exception. The caller analyses the func return
! values. */
!
! if (!caught || (mask & RETURN_MASK (caught)))
! {
! *func_val = val;
! *func_caught = caught;
! return;
! }
! /* The caller didn't request that the event be caught, relay the
event to the next containing catch_errors(). */
! return_to_top_level (caught);
! }
! int
! catch_exceptions (struct ui_out *uiout,
! catch_exceptions_ftype *func,
! void *func_args,
! char *errstring,
! return_mask mask)
! {
! int val;
! enum return_reason caught;
! catcher (func, uiout, func_args, &val, &caught, errstring, mask);
! gdb_assert (val >= 0);
! gdb_assert (caught <= 0);
! if (caught < 0)
! return caught;
! return val;
! }
! struct catch_errors_args
! {
! catch_errors_ftype *func;
! void *func_args;
! };
! int
! do_catch_errors (struct ui_out *uiout, void *data)
! {
! struct catch_errors_args *args = data;
! return args->func (args->func_args);
! }
! int
! catch_errors (catch_errors_ftype *func, void *func_args, char *errstring,
! return_mask mask)
! {
! int val;
! enum return_reason caught;
! struct catch_errors_args args;
! args.func = func;
! args.func_args = func_args;
! catcher (do_catch_errors, uiout, &args, &val, &caught, errstring, mask);
! if (caught != 0)
! return 0;
! return val;
}
struct captured_command_args