From 99eeeb0ff7898f8987188e510b2612de1fcfa454 Mon Sep 17 00:00:00 2001 From: Nicholas Duffek Date: Thu, 24 Feb 2000 00:04:03 +0000 Subject: [PATCH] * top.c (SIGJMP_BUF, SIGSETJMP, SIGLONGJMP): Update comments. (error_return, quit_return): Merge into catch_return pointer. (return_to_top_level): Update comment. Longjmp to *catch_errors, and communicate reason to catch_errors via setjmp return value. (catch_errors): Always catch both quit and error, and if a catch wasn't requested by caller, throw it to the next catch_error. Replace dual longjmp buffer memcpy with single pointer change. Add FIXME for possibly adding new interface to tell caller what event was caught. Add extensive comments. * defs.h (enum return_reason): Reserve 0 for use as initial setjmp() return value. (RETURN_MASK): New public macro to generate RETURN_MASK_* from enum return_reason. (RETURN_MASK_QUIT, RETURN_MASK_ERROR): Define using RETURN_MASK. --- gdb/ChangeLog | 17 +++++++ gdb/defs.h | 13 +++-- gdb/top.c | 135 +++++++++++++++++++++++++++++--------------------- 3 files changed, 103 insertions(+), 62 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c861278f201..eed3df14444 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +Wed Feb 23 19:01:45 EST 2000 Nicholas Duffek + + * top.c (SIGJMP_BUF, SIGSETJMP, SIGLONGJMP): Update comments. + (error_return, quit_return): Merge into catch_return pointer. + (return_to_top_level): Update comment. Longjmp to *catch_errors, + and communicate reason to catch_errors via setjmp return value. + (catch_errors): Always catch both quit and error, and if a catch + wasn't requested by caller, throw it to the next catch_error. + Replace dual longjmp buffer memcpy with single pointer change. + Add FIXME for possibly adding new interface to tell caller what + event was caught. Add extensive comments. + * defs.h (enum return_reason): Reserve 0 for use as initial + setjmp() return value. + (RETURN_MASK): New public macro to generate RETURN_MASK_* from + enum return_reason. + (RETURN_MASK_QUIT, RETURN_MASK_ERROR): Define using RETURN_MASK. + 2000-02-23 Fernando Nasser * infcmd.c (run_stack_dummy): Do not pop frame on random signal. diff --git a/gdb/defs.h b/gdb/defs.h index fa9f540462a..c4756f162ce 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -801,21 +801,24 @@ extern NORETURN void internal_error (char *, ...) ATTR_NORETURN; extern NORETURN void nomem (long) ATTR_NORETURN; -/* Reasons for calling return_to_top_level. */ +/* 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, + RETURN_QUIT = 1, /* Any other error. */ RETURN_ERROR }; #define ALL_CLEANUPS ((struct cleanup *)0) -#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT) -#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR) -#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) +#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; extern NORETURN void return_to_top_level (enum return_reason) ATTR_NORETURN; diff --git a/gdb/top.c b/gdb/top.c index 6bd7648e08c..4acf4db4ad6 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -482,8 +482,8 @@ NORETURN void (*error_hook) PARAMS ((void)) ATTR_NORETURN; -/* Generally one should use catch_errors rather than manipulating these - directly. The exception is main(). */ +/* One should use catch_errors rather than manipulating these + directly. */ #if defined(HAVE_SIGSETJMP) #define SIGJMP_BUF sigjmp_buf #define SIGSETJMP(buf) sigsetjmp(buf, 1) @@ -494,13 +494,10 @@ PARAMS ((void)) ATTR_NORETURN; #define SIGLONGJMP(buf,val) longjmp(buf,val) #endif -/* Where to go for return_to_top_level (RETURN_ERROR). */ -static SIGJMP_BUF error_return; -/* Where to go for return_to_top_level (RETURN_QUIT). */ -static SIGJMP_BUF quit_return; +/* Where to go for return_to_top_level. */ +static SIGJMP_BUF *catch_return; -/* Return for reason REASON. This generally gets back to the command - loop, but can be caught via catch_errors. */ +/* Return for reason REASON to the nearest containing catch_errors(). */ NORETURN void return_to_top_level (reason) @@ -531,8 +528,11 @@ return_to_top_level (reason) break; } - (NORETURN void) SIGLONGJMP - (reason == RETURN_ERROR ? error_return : quit_return, 1); + /* 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. */ + + (NORETURN void) SIGLONGJMP (*catch_return, (int)reason); } /* Call FUNC with arg ARGS, catching any errors. If there is no @@ -562,13 +562,6 @@ return_to_top_level (reason) code also randomly used a SET_TOP_LEVEL macro that directly initialize the longjmp buffers. */ -/* MAYBE: cagney/1999-11-05: Since the SET_TOP_LEVEL macro has been - eliminated it is now possible to use the stack to directly store - each longjmp buffer. The global code would just need to update a - pointer (onto the stack - ulgh!?) indicating the current longjmp - buffers. It would certainly improve the performance of the longjmp - code since the memcpy's would be eliminated. */ - /* MAYBE: cagney/1999-11-05: Should the catch_erros and cleanups code be consolidated into a single file instead of being distributed between utils.c and top.c? */ @@ -580,61 +573,89 @@ catch_errors (func, args, errstring, mask) char *errstring; return_mask mask; { - SIGJMP_BUF saved_error; - SIGJMP_BUF saved_quit; - SIGJMP_BUF tmp_jmp; + SIGJMP_BUF *saved_catch; + SIGJMP_BUF catch; int val; struct cleanup *saved_cleanup_chain; char *saved_error_pre_print; char *saved_quit_pre_print; - saved_cleanup_chain = save_cleanups (); + /* 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; saved_quit_pre_print = quit_pre_print; if (mask & RETURN_MASK_ERROR) - { - memcpy ((char *) saved_error, (char *) error_return, sizeof (SIGJMP_BUF)); - error_pre_print = errstring; - } + error_pre_print = errstring; if (mask & RETURN_MASK_QUIT) - { - memcpy (saved_quit, quit_return, sizeof (SIGJMP_BUF)); - quit_pre_print = errstring; - } + quit_pre_print = errstring; - if (SIGSETJMP (tmp_jmp) == 0) - { - if (mask & RETURN_MASK_ERROR) - memcpy (error_return, tmp_jmp, sizeof (SIGJMP_BUF)); - if (mask & RETURN_MASK_QUIT) - memcpy (quit_return, tmp_jmp, sizeof (SIGJMP_BUF)); - val = (*func) (args); - /* FIXME: cagney/1999-11-05: A correct FUNC implementaton will - clean things up (restoring the cleanup chain) to the state - they were just prior to the call. Technically, this means - that the below restore_cleanups call is redundant. - Unfortunatly, many FUNC's are not that well behaved. - restore_cleanups should either be replaced with a do_cleanups - call (to cover the problem) or an assertion check to detect - bad FUNCs code. */ - } - else - val = 0; + /* Prevent error/quit during FUNC from calling cleanups established + prior to here. */ + + saved_cleanup_chain = save_cleanups (); + + /* Call FUNC, catching error/quit events. */ + + saved_catch = catch_return; + catch_return = &catch; + caught = SIGSETJMP (catch); + if (!caught) + val = (*func) (args); + catch_return = saved_catch; + + /* FIXME: cagney/1999-11-05: A correct FUNC implementaton will + clean things up (restoring the cleanup chain) to the state they + were just prior to the call. Unfortunatly, many FUNC's are not + that well behaved. This could be fixed by adding either a + 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_ERROR) - { - memcpy (error_return, saved_error, sizeof (SIGJMP_BUF)); - error_pre_print = saved_error_pre_print; - } if (mask & RETURN_MASK_QUIT) - { - memcpy (quit_return, saved_quit, sizeof (SIGJMP_BUF)); - quit_pre_print = saved_quit_pre_print; - } - return val; + 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 -- 2.30.2