diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2005-11-16 17:04:41 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@gcc.gnu.org> | 2005-11-16 17:04:41 +0000 |
commit | 1dcca6f3616f620f7ac81e9f4b814b06b246b093 (patch) | |
tree | 334b3d2a842b79dc3b040fb2439effee2404892f /gcc/config/arm | |
parent | 8656214b84c3e789deffe8f7b465bd1c886b2a03 (diff) | |
download | gcc-1dcca6f3616f620f7ac81e9f4b814b06b246b093.zip gcc-1dcca6f3616f620f7ac81e9f4b814b06b246b093.tar.gz gcc-1dcca6f3616f620f7ac81e9f4b814b06b246b093.tar.bz2 |
unwind-arm.h: Reorder interface function declarations.
2005-11-16 Nathan Sidwell <nathan@codesourcery.com>
gcc/
* config/arm/unwind-arm.h: Reorder interface function declarations.
(_URC_END_OF_STACK): New enumeration value.
(_US_UNWIND_ACTION_MASK, _US_FORCE_UNWIND, _US_END_OF_STACK): Likewise.
(struct _Unwind_Control_Block): Document reserved field use.
(_Unwind_Stop_Fn): New typedef.
(_Unwind_ForcedUnwind): Declare.
(_Unwind_Resume_or_Rethrow): Declare.
* config/arm/libunwind.S (UNWIND_WRAPER): Add nargs
argument. Adjust.
(_Unwind_Resume_or_Rethrow, _Unwind_ForcedUnwind): New.
* config/arm/unwind-arm.c (UCB_FORCED_STOP_FN)
(UCB_FORCED_STOP_ARG): New.
(search_EIT_table): Update boundary condition checks.
(get_eit_entry): Return _URC_END_OF_STACK when cannot unwind.
(unwind_phase2): Replace for with do..while.
(unwind_phase2_forced): New.
(__gnu_Unwind_RaiseException): Replace for with do..while.
(__gnu_Unwind_ForcedUnwind): New.
(__gnu_Unwind_Resume): Set FORCE_UNWIND flag, if forced unwinding.
Use appropriate phase2 unwinder.
(__gnu_Unwind_Resume_or_Rethrow): New.
(__gnu_unwind_pr_common): Cope with forced unwinding.
gcc/testsuite/
* g++.dg/eh/forced1.C: Adjust to cope with ARM EABI
structures.
* g++.dg/eh/forced2.C: Likewise.
* g++.dg/eh/forced3.C: Likewise.
* g++.dg/eh/forced4.C: Likewise.
libstdc++-v3/
* libsupc++/eh_arm.cc (__cxa_begin_cleanup): Remember a
foreign exception too.
(__gnu_end_cleanup): Recover a foreign exception too.
* libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Cope
with forced unwinding.
* libsupc++/eh_throw.cc (__cxxabiv1::__cxa_rethrow): Use
_Unwind_Resume_or_Rethrow for ARM EABI.
From-SVN: r107089
Diffstat (limited to 'gcc/config/arm')
-rw-r--r-- | gcc/config/arm/libunwind.S | 12 | ||||
-rw-r--r-- | gcc/config/arm/unwind-arm.c | 130 | ||||
-rw-r--r-- | gcc/config/arm/unwind-arm.h | 73 |
3 files changed, 160 insertions, 55 deletions
diff --git a/gcc/config/arm/libunwind.S b/gcc/config/arm/libunwind.S index 8d226df..06e1310 100644 --- a/gcc/config/arm/libunwind.S +++ b/gcc/config/arm/libunwind.S @@ -78,7 +78,7 @@ ARM_FUNC_START gnu_Unwind_Save_VFP /* Wrappers to save core registers, then call the real routine. */ -.macro UNWIND_WRAPPER name +.macro UNWIND_WRAPPER name nargs ARM_FUNC_START \name /* Create a phase2_vrs structure. */ /* Split reg push in two to ensure the correct value for sp. */ @@ -89,8 +89,8 @@ ARM_FUNC_START gnu_Unwind_Save_VFP mov r3, #0 stmfd sp!, {r2, r3} - /* Point r1 at the block. Pass r0 unchanged. */ - add r1, sp, #4 + /* Point r1 at the block. Pass r[0..nargs) unchanged. */ + add r\nargs, sp, #4 #if defined(__thumb__) /* Switch back to thumb mode to avoid interworking hassle. */ adr ip, .L1_\name @@ -112,7 +112,9 @@ ARM_FUNC_START gnu_Unwind_Save_VFP UNPREFIX \name .endm -UNWIND_WRAPPER _Unwind_RaiseException -UNWIND_WRAPPER _Unwind_Resume +UNWIND_WRAPPER _Unwind_RaiseException 1 +UNWIND_WRAPPER _Unwind_Resume 1 +UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1 +UNWIND_WRAPPER _Unwind_ForcedUnwind 3 #endif /* __symbian__ */ diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c index e436f7c..4d703db 100644 --- a/gcc/config/arm/unwind-arm.c +++ b/gcc/config/arm/unwind-arm.c @@ -51,8 +51,10 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); #define EXIDX_CANTUNWIND 1 #define uint32_highbit (((_uw) 1) << 31) +#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1) #define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) #define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) +#define UCB_FORCED_STOP_ARG(ucb) ((ucbp)->unwinder_cache.reserved4) struct core_regs { @@ -356,9 +358,9 @@ search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) n = (left + right) / 2; this_fn = selfrel_offset31 (&table[n].fnoffset); if (n != nrec - 1) - next_fn = selfrel_offset31 (&table[n + 1].fnoffset); + next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1; else - next_fn = ~(_uw) 0; + next_fn = (_uw)0 - 1; if (return_address < this_fn) { @@ -366,7 +368,7 @@ search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) return (__EIT_entry *) 0; right = n - 1; } - else if (return_address < next_fn) + else if (return_address <= next_fn) return &table[n]; else left = n + 1; @@ -419,7 +421,7 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) if (eitp->content == EXIDX_CANTUNWIND) { UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; + return _URC_END_OF_STACK; } /* Obtain the address of the "real" __EHT_Header word. */ @@ -472,21 +474,19 @@ unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs) { _Unwind_Reason_Code pr_result; - for(;;) + do { /* Find the entry for this routine. */ if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK) abort (); UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC]; - + /* Call the pr to decide what to do. */ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); - - if (pr_result != _URC_CONTINUE_UNWIND) - break; } + while (pr_result == _URC_CONTINUE_UNWIND); if (pr_result != _URC_INSTALL_CONTEXT) abort(); @@ -494,6 +494,57 @@ unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs) restore_core_regs (&vrs->core); } +/* Perform phase2 forced unwinding. */ + +static _Unwind_Reason_Code +unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs) +{ + _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp); + void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp); + _Unwind_Reason_Code pr_result; + + /* Unwind until we reach a propagation barrier. */ + do + { + _Unwind_State action; + _Unwind_Reason_Code entry_code; + _Unwind_Reason_Code stop_code; + + /* Find the entry for this routine. */ + entry_code = get_eit_entry (ucbp, entry_vrs->core.r[R_PC]); + + action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND; + if (entry_code == _URC_END_OF_STACK) + action |= _US_END_OF_STACK; + else if (entry_code != _URC_OK) + return _URC_FAILURE; + + stop_code = stop_fn (1, action, ucbp->exception_class, ucbp, + (void *)entry_vrs, stop_arg); + if (stop_code != _URC_NO_REASON) + return _URC_FAILURE; + + if (entry_code == _URC_END_OF_STACK) + return entry_code; + + UCB_SAVED_CALLSITE_ADDR (ucbp) = entry_vrs->core.r[R_PC]; + + /* Call the pr to decide what to do. */ + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) + (action, ucbp, (void *) entry_vrs); + } + while (pr_result == _URC_CONTINUE_UNWIND); + + if (pr_result != _URC_INSTALL_CONTEXT) + { + /* Some sort of failure has occurred in the pr and probably the + pr returned _URC_FAILURE. */ + return _URC_FAILURE; + } + + restore_core_regs (&entry_vrs->core); +} + /* Perform phase1 unwinding. UCBP is the exception being thrown, and entry_VRS is the register state on entry to _Unwind_RaiseException. */ @@ -516,7 +567,7 @@ __gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, saved_vrs.demand_save_flags = ~(_uw) 0; /* Unwind until we reach a propagation barrier. */ - for (;;) + do { /* Find the entry for this routine. */ if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) @@ -525,10 +576,8 @@ __gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, /* Call the pr to decide what to do. */ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); - - if (pr_result != _URC_CONTINUE_UNWIND) - break; } + while (pr_result == _URC_CONTINUE_UNWIND); /* We've unwound as far as we want to go, so restore the original register state. */ @@ -547,19 +596,42 @@ __gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, being thrown and ENTRY_VRS is the register state on entry to _Unwind_Resume. */ _Unwind_Reason_Code +__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp, + _Unwind_Stop_Fn stop_fn, void *stop_arg, + phase2_vrs *entry_vrs) +{ + UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn; + UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg; + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + + return unwind_phase2_forced (ucbp, entry_vrs); +} + +_Unwind_Reason_Code __gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *); _Unwind_Reason_Code __gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs) { _Unwind_Reason_Code pr_result; + _Unwind_State action; /* Recover the saved address. */ entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp); - + /* Call the cached PR. */ + action = _US_UNWIND_FRAME_RESUME; + if (UCB_FORCED_STOP_FN (ucbp)) + action |= _US_FORCE_UNWIND; + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) - (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); + (action, ucbp, (_Unwind_Context *) entry_vrs); switch (pr_result) { @@ -569,13 +641,32 @@ __gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs) case _URC_CONTINUE_UNWIND: /* Continue unwinding the next frame. */ - unwind_phase2 (ucbp, entry_vrs); + if (UCB_FORCED_STOP_FN (ucbp)) + return unwind_phase2_forced (ucbp, entry_vrs); + else + unwind_phase2 (ucbp, entry_vrs); default: abort (); } } +_Unwind_Reason_Code +__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp, + phase2_vrs * entry_vrs) +{ + if (!UCB_FORCED_STOP_FN (ucbp)) + return __gnu_Unwind_RaiseException (ucbp, entry_vrs); + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + /* Continue unwinding the next frame. */ + return unwind_phase2_forced (ucbp, entry_vrs); +} + /* Clean up an exception object when unwinding is complete. */ void _Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused))) @@ -619,6 +710,9 @@ __gnu_unwind_pr_common (_Unwind_State state, _uw rtti_count; int phase2_call_unexpected_after_unwind = 0; int in_range = 0; + int forced_unwind = state & _US_FORCE_UNWIND; + + state &= _US_ACTION_MASK; data = (_uw *) ucbp->pr_cache.ehtp; uws.data = *(data++); @@ -748,9 +842,9 @@ __gnu_unwind_pr_common (_Unwind_State state, /* Exception specification. */ if (state == _US_VIRTUAL_UNWIND_FRAME) { - if (in_range) + if (in_range && (!forced_unwind || !rtti_count)) { - /* Match against teh exception specification. */ + /* Match against the exception specification. */ _uw i; _uw rtti; void *matched; diff --git a/gcc/config/arm/unwind-arm.h b/gcc/config/arm/unwind-arm.h index 4d86407..f0c545f 100644 --- a/gcc/config/arm/unwind-arm.h +++ b/gcc/config/arm/unwind-arm.h @@ -1,5 +1,5 @@ /* Header file for the ARM EABI unwinder - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Paul Brook This file is free software; you can redistribute it and/or modify it @@ -54,28 +54,41 @@ extern "C" { { _URC_OK = 0, /* operation completed successfully */ _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_END_OF_STACK = 5, _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8, _URC_FAILURE = 9 /* unspecified failure of some kind */ } _Unwind_Reason_Code; - + typedef enum { _US_VIRTUAL_UNWIND_FRAME = 0, _US_UNWIND_FRAME_STARTING = 1, - _US_UNWIND_FRAME_RESUME = 2 + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16 } _Unwind_State; - + + /* Provided only for for compatibility with existing code. */ + typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 +#define _UA_END_OF_STACK 16 +#define _URC_NO_REASON _URC_OK + typedef struct _Unwind_Control_Block _Unwind_Control_Block; typedef struct _Unwind_Context _Unwind_Context; typedef _uw _Unwind_EHT_Header; - - + + /* UCB: */ - + struct _Unwind_Control_Block { char exception_class[8]; @@ -83,10 +96,10 @@ extern "C" { /* Unwinder cache, private fields for the unwinder's use */ struct { - _uw reserved1; /* init reserved1 to 0, then don't touch */ - _uw reserved2; - _uw reserved3; - _uw reserved4; + _uw reserved1; /* Forced unwind stop fn, 0 if not forced */ + _uw reserved2; /* Personality routine address */ + _uw reserved3; /* Saved callsite address */ + _uw reserved4; /* Forced unwind stop arg */ _uw reserved5; } unwinder_cache; @@ -114,14 +127,9 @@ extern "C" { pr_cache; long long int :0; /* Force alignment to 8-byte boundary */ }; - - /* Interface functions: */ - _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); - void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); - void _Unwind_Complete(_Unwind_Control_Block *ucbp); /* Virtual Register Set*/ - + typedef enum { _UVRSC_CORE = 0, /* integer register */ @@ -131,7 +139,7 @@ extern "C" { _UVRSC_WMMXC = 4 /* Intel WMMX control register */ } _Unwind_VRS_RegClass; - + typedef enum { _UVRSD_UINT32 = 0, @@ -142,13 +150,13 @@ extern "C" { _UVRSD_DOUBLE = 5 } _Unwind_VRS_DataRepresentation; - + typedef enum { _UVRSR_OK = 0, _UVRSR_NOT_IMPLEMENTED = 1, _UVRSR_FAILED = 2 - } + } _Unwind_VRS_Result; /* Frame unwinding state. */ @@ -171,11 +179,11 @@ extern "C" { _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, _uw, _Unwind_VRS_DataRepresentation, void *); - + _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, _uw, _Unwind_VRS_DataRepresentation, void *); - + _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, _uw, _Unwind_VRS_DataRepresentation); @@ -200,6 +208,17 @@ extern "C" { abort (); } + /* Interface functions: */ + _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); + void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + + typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int, _Unwind_Action, _Unwind_Exception_Class, + _Unwind_Control_Block *, struct _Unwind_Context *, void *); + _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *); + void _Unwind_Complete(_Unwind_Control_Block *ucbp); void _Unwind_DeleteException (_Unwind_Exception *); _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, @@ -254,16 +273,6 @@ extern "C" { #define _Unwind_SetIP(context, val) \ _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) - /* Provided only for for compatibility with existing code. */ - typedef int _Unwind_Action; -#define _UA_SEARCH_PHASE 1 -#define _UA_CLEANUP_PHASE 2 -#define _UA_HANDLER_FRAME 4 -#define _UA_FORCE_UNWIND 8 -#define _UA_END_OF_STACK 16 - -#define _URC_NO_REASON _URC_OK - #ifdef __cplusplus } /* extern "C" */ #endif |