diff options
author | Arnaud Charlet <charlet@gcc.gnu.org> | 2014-01-20 15:00:29 +0100 |
---|---|---|
committer | Arnaud Charlet <charlet@gcc.gnu.org> | 2014-01-20 15:00:29 +0100 |
commit | 51b0e05ae4a0c5a4ef37e52f8e1702b02e6d8f72 (patch) | |
tree | eaacabf5dfb722e9027b148fe423cbed60052d8c /gcc/ada/raise-gcc.c | |
parent | 5ff90f08f4ccef07ca580c63a7ee5aa896d45527 (diff) | |
download | gcc-51b0e05ae4a0c5a4ef37e52f8e1702b02e6d8f72.zip gcc-51b0e05ae4a0c5a4ef37e52f8e1702b02e6d8f72.tar.gz gcc-51b0e05ae4a0c5a4ef37e52f8e1702b02e6d8f72.tar.bz2 |
[multiple changes]
2014-01-20 Tristan Gingold <gingold@adacore.com>
* raise-gcc.c (exception_class_eq): New function.
(is_handled_by): Use it to compare exception classes.
(PERSONALITY_STORAGE): Define. (continue_unwind): New function to
be called to return URC_CONTINUE_UNWIND.
(personality_body): New function, extracted from PERSONALITY_ROUTINE.
(PERSONALITY_ROUTINE): Add an implementation for the ARM unwinder.
2014-01-20 Robert Dewar <dewar@adacore.com>
* opt.ads: Minor comment update.
From-SVN: r206815
Diffstat (limited to 'gcc/ada/raise-gcc.c')
-rw-r--r-- | gcc/ada/raise-gcc.c | 241 |
1 files changed, 174 insertions, 67 deletions
diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c index ca1e84a..53fc070 100644 --- a/gcc/ada/raise-gcc.c +++ b/gcc/ada/raise-gcc.c @@ -212,7 +212,7 @@ db_phases (int phases) { const phase_descriptor *a = phase_descriptors; - if (! (db_accepted_codes() & DB_PHASES)) + if (! (db_accepted_codes () & DB_PHASES)) return; db (DB_PHASES, "\n"); @@ -860,15 +860,33 @@ extern struct Exception_Data Foreign_Exception; extern struct Exception_Data Non_Ada_Error; #endif +/* Return true iff the exception class of EXCEPT is EC. */ + +static int +exception_class_eq (const _GNAT_Exception *except, unsigned long long ec) +{ +#ifdef __ARM_EABI_UNWINDER__ + union { + char exception_class[8]; + unsigned long long ec; + } u; + + u.ec = ec; + return memcmp (except->common.exception_class, u.exception_class, 8) == 0; +#else + return except->common.exception_class == ec; +#endif +} + static enum action_kind -is_handled_by (_Unwind_Ptr choice, _GNAT_Exception * propagated_exception) +is_handled_by (_Unwind_Ptr choice, _GNAT_Exception *propagated_exception) { /* All others choice match everything. */ if (choice == GNAT_ALL_OTHERS) return handler; /* GNAT exception occurrence. */ - if (propagated_exception->common.exception_class == GNAT_EXCEPTION_CLASS) + if (exception_class_eq (propagated_exception, GNAT_EXCEPTION_CLASS)) { /* Pointer to the GNAT exception data corresponding to the propagated occurrence. */ @@ -913,7 +931,7 @@ is_handled_by (_Unwind_Ptr choice, _GNAT_Exception * propagated_exception) return handler; /* C++ exception occurrences. */ - if (propagated_exception->common.exception_class == CXX_EXCEPTION_CLASS + if (exception_class_eq (propagated_exception, CXX_EXCEPTION_CLASS) && Language_For (choice) == 'C') { void *choice_typeinfo = Foreign_Data_For (choice); @@ -1070,14 +1088,120 @@ extern void __gnat_notify_unhandled_exception (struct Exception_Occurrence *); /* Below is the eh personality routine per se. We currently assume that only GNU-Ada exceptions are met. */ +/* By default, the personality routine is public. */ +#define PERSONALITY_STORAGE + #ifdef __USING_SJLJ_EXCEPTIONS__ #define PERSONALITY_FUNCTION __gnat_personality_sj0 #elif defined (__SEH__) #define PERSONALITY_FUNCTION __gnat_personality_imp +/* The public personality routine for seh is __gnat_personality_seh0, defined + below using the SEH convention. This is a wrapper around the GNU routine, + which is static. */ +#undef PERSONALITY_STORAGE +#define PERSONALITY_STORAGE static #else #define PERSONALITY_FUNCTION __gnat_personality_v0 #endif +/* Code executed to continue unwinding. With the ARM unwinder, the + personality routine must unwind one frame. */ + +static _Unwind_Reason_Code +continue_unwind (struct _Unwind_Exception* ue_header, + struct _Unwind_Context* uw_context) +{ +#ifdef __ARM_EABI_UNWINDER__ + if (__gnu_unwind_frame (ue_header, uw_context) != _URC_OK) + return _URC_FAILURE; +#endif + return _URC_CONTINUE_UNWIND; +} + +/* Common code for the body of GNAT personality routine. This code is shared + between all unwinders. */ + +static _Unwind_Reason_Code +personality_body (_Unwind_Action uw_phases, + _Unwind_Exception *uw_exception, + _Unwind_Context *uw_context) +{ + region_descriptor region; + action_descriptor action; + _Unwind_Ptr ip; + + /* Debug traces. */ + db_indent (DB_INDENT_RESET); + db_phases (uw_phases); + db_indent (DB_INDENT_INCREASE); + + /* Get the region description for the context we were provided with. This + will tell us if there is some lsda, call_site, action and/or ttype data + for the associated ip. */ + get_region_description_for (uw_context, ®ion); + + /* No LSDA => no handlers or cleanups => we shall unwind further up. */ + if (! region.lsda) + return continue_unwind (uw_exception, uw_context); + + /* Get the instruction pointer. */ + ip = get_ip_from_context (uw_context); + db_region_for (®ion, ip); + + /* Search the call-site and action-record tables for the action associated + with this IP. */ + get_action_description_for (ip, uw_exception, uw_phases, ®ion, &action); + db_action_for (&action, ip); + + /* Whatever the phase, if there is nothing relevant in this frame, + unwinding should just go on. */ + if (action.kind == nothing) + return continue_unwind (uw_exception, uw_context); + + /* If we found something in search phase, we should return a code indicating + what to do next depending on what we found. If we only have cleanups + around, we shall try to unwind further up to find a handler, otherwise, + tell we have a handler, which will trigger the second phase. */ + if (uw_phases & _UA_SEARCH_PHASE) + { + if (action.kind == cleanup) + { + return continue_unwind (uw_exception, uw_context); + } + else + { + struct Exception_Occurrence *excep; + + /* Trigger the appropriate notification routines before the second + phase starts, which ensures the stack is still intact. + First, setup the Ada occurrence. */ + excep = __gnat_setup_current_excep (uw_exception); + if (action.kind == unhandler) + __gnat_notify_unhandled_exception (excep); + else + __gnat_notify_handled_exception (excep); + + return _URC_HANDLER_FOUND; + } + } + + /* We found something in cleanup/handler phase, which might be the handler + or a cleanup for a handled occurrence, or a cleanup for an unhandled + occurrence (we are in a FORCED_UNWIND phase in this case). Install the + context to get there. */ + + setup_to_install + (uw_context, uw_exception, action.landing_pad, action.ttype_filter); + + /* Write current exception, so that it can be retrieved from Ada. It was + already done during phase 1 (just above), but in between, one or several + exceptions may have been raised (in cleanup handlers). */ + __gnat_setup_current_excep (uw_exception); + + return _URC_INSTALL_CONTEXT; +} + +#ifndef __ARM_EABI_UNWINDER__ /* Major tweak for ia64-vms : the CHF propagation phase calls this personality routine with sigargs/mechargs arguments and has very specific expectations on possible return values. @@ -1109,15 +1233,12 @@ typedef int version_arg_t; typedef _Unwind_Action phases_arg_t; #endif -#if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) -static -#endif -_Unwind_Reason_Code +PERSONALITY_STORAGE _Unwind_Reason_Code PERSONALITY_FUNCTION (version_arg_t, phases_arg_t, _Unwind_Exception_Class, _Unwind_Exception *, _Unwind_Context *); -_Unwind_Reason_Code +PERSONALITY_STORAGE _Unwind_Reason_Code PERSONALITY_FUNCTION (version_arg_t version_arg, phases_arg_t phases_arg, _Unwind_Exception_Class uw_exception_class @@ -1157,73 +1278,59 @@ PERSONALITY_FUNCTION (version_arg_t version_arg, return _URC_FATAL_PHASE1_ERROR; } - db_indent (DB_INDENT_RESET); - db_phases (uw_phases); - db_indent (DB_INDENT_INCREASE); - - /* Get the region description for the context we were provided with. This - will tell us if there is some lsda, call_site, action and/or ttype data - for the associated ip. */ - get_region_description_for (uw_context, ®ion); - ip = get_ip_from_context (uw_context); - db_region_for (®ion, ip); + return personality_body (uw_phases, uw_exception, uw_context); +} - /* No LSDA => no handlers or cleanups => we shall unwind further up. */ - if (! region.lsda) - return _URC_CONTINUE_UNWIND; +#else /* __ARM_EABI_UNWINDER__ */ - /* Search the call-site and action-record tables for the action associated - with this IP. */ - get_action_description_for (ip, uw_exception, uw_phases, ®ion, &action); - db_action_for (&action, ip); +PERSONALITY_STORAGE _Unwind_Reason_Code +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception* ue_header, + struct _Unwind_Context* uw_context); - /* Whatever the phase, if there is nothing relevant in this frame, - unwinding should just go on. */ - if (action.kind == nothing) - return _URC_CONTINUE_UNWIND; +PERSONALITY_STORAGE _Unwind_Reason_Code +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception* uw_exception, + struct _Unwind_Context* uw_context) +{ + _Unwind_Action uw_phases; + region_descriptor region; + action_descriptor action; + _Unwind_Ptr ip; - /* If we found something in search phase, we should return a code indicating - what to do next depending on what we found. If we only have cleanups - around, we shall try to unwind further up to find a handler, otherwise, - tell we have a handler, which will trigger the second phase. */ - if (uw_phases & _UA_SEARCH_PHASE) + switch (state & _US_ACTION_MASK) { - if (action.kind == cleanup) - { - return _URC_CONTINUE_UNWIND; - } - else - { - struct Exception_Occurrence *excep; - - /* Trigger the appropriate notification routines before the second - phase starts, which ensures the stack is still intact. - First, setup the Ada occurrence. */ - excep = __gnat_setup_current_excep (uw_exception); - if (action.kind == unhandler) - __gnat_notify_unhandled_exception (excep); - else - __gnat_notify_handled_exception (excep); - - return _URC_HANDLER_FOUND; - } + case _US_VIRTUAL_UNWIND_FRAME: + /* Phase 1. */ + uw_phases = _UA_SEARCH_PHASE; + break; + + case _US_UNWIND_FRAME_STARTING: + uw_phases = _UA_CLEANUP_PHASE; + if (!(state & _US_FORCE_UNWIND) + && (uw_exception->barrier_cache.sp + == _Unwind_GetGR (uw_context, UNWIND_STACK_REG))) + uw_phases |= _UA_HANDLER_FRAME; + break; + + case _US_UNWIND_FRAME_RESUME: + return continue_unwind (uw_exception, uw_context); + + default: + return _URC_FAILURE; } + uw_phases |= (state & _US_FORCE_UNWIND); - /* We found something in cleanup/handler phase, which might be the handler - or a cleanup for a handled occurrence, or a cleanup for an unhandled - occurrence (we are in a FORCED_UNWIND phase in this case). Install the - context to get there. */ + /* The dwarf unwinder assumes the context structure holds things like the + function and LSDA pointers. The ARM implementation caches these in + the exception header (UCB). To avoid rewriting everything we make a + virtual scratch register point at the UCB. This is a GNU specific + requirement. */ + _Unwind_SetGR (uw_context, UNWIND_POINTER_REG, (_Unwind_Ptr) uw_exception); - setup_to_install - (uw_context, uw_exception, action.landing_pad, action.ttype_filter); - - /* Write current exception, so that it can be retrieved from Ada. It was - already done during phase 1 (just above), but in between, one or several - exceptions may have been raised (in cleanup handlers). */ - __gnat_setup_current_excep (uw_exception); - - return _URC_INSTALL_CONTEXT; + return personality_body (uw_phases, uw_exception, uw_context); } +#endif /* __ARM_EABI_UNWINDER__ */ /* Callback routine called by Unwind_ForcedUnwind to execute all the cleanup before exiting the task. */ |