This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ARM forced unwinding for HEAD part 1
- From: Daniel Jacobowitz <drow at false dot org>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard Earnshaw <Richard dot Earnshaw at arm dot com>,Nathan Sidwell <nathan at codesourcery dot com>,Paul Brook <paul at codesourcery dot com>
- Date: Mon, 14 Nov 2005 11:51:08 -0500
- Subject: ARM forced unwinding for HEAD part 1
This patch is a backport of Nathan's forced unwinding implementation, which
Paul already approved for csl-arm-branch, to HEAD. I've now updated NPTL to
use the new implementation and found various problems with it; I'm going to
be posting those in a second so that they can be reviewed separately.
I realize this patch is very late, but it is the final part of the ARM EABI
GNU/Linux configuration, and I can see no way that I could have broken any
existing configuration. Is this OK for mainline, assuming the followups are
approved?
--
Daniel Jacobowitz
CodeSourcery, LLC
2005-11-14 Nathan Sidwell <nathan@codesourcery.com>
* gcc/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.
* gcc/config/arm/libunwind.S (UNWIND_WRAPER): Add nargs
argument. Adjust.
(_Unwind_Resume_or_Rethrow, _Unwind_ForcedUnwind): New.
* gcc/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.
* gcc/testsuite/g++.dg/eh/forced2.C: Likewise.
* gcc/testsuite/g++.dg/eh/forced3.C: Likewise.
* gcc/testsuite/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.
* libstdc++-v3/libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Cope
with forced unwinding.
* libstdc++-v3/libsupc++/eh_throw.cc (__cxxabiv1::__cxa_rethrow): Use
_Unwind_Resume_or_Rethrow for ARM EABI.
Index: gcc/gcc/config/arm/unwind-arm.h
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.h 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.h 2005-11-14 10:51:09.000000000 -0500
@@ -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
@@ -39,7 +39,7 @@ extern "C" {
#endif
/* We add a prototype for abort here to avoid creating a dependency on
target headers. */
- extern void abort();
+ extern void abort ();
typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
@@ -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
Index: gcc/gcc/config/arm/libunwind.S
===================================================================
--- gcc.orig/gcc/config/arm/libunwind.S 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/libunwind.S 2005-11-14 10:51:09.000000000 -0500
@@ -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__ */
Index: gcc/gcc/config/arm/unwind-arm.c
===================================================================
--- gcc.orig/gcc/config/arm/unwind-arm.c 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/config/arm/unwind-arm.c 2005-11-14 10:51:09.000000000 -0500
@@ -51,8 +51,10 @@ __gnu_Unwind_Find_exidx (_Unwind_Ptr, in
#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 * ta
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 * ta
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 *uc
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 * u
{
_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 * u
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_Con
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_Con
/* 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_Con
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_Blo
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 st
_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 st
/* 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;
Index: gcc/gcc/testsuite/g++.dg/eh/forced1.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced1.C 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced1.C 2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
#include <unwind.h>
#include <stdlib.h>
+#include <string.h>
static int test = 0;
@@ -35,7 +36,8 @@ force_unwind_cleanup (_Unwind_Reason_Cod
static void force_unwind ()
{
_Unwind_Exception *exc = new _Unwind_Exception;
- exc->exception_class = 0;
+ // exception_class might not be a scalar.
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
exc->exception_cleanup = force_unwind_cleanup;
#ifndef __USING_SJLJ_EXCEPTIONS__
@@ -54,7 +56,7 @@ struct S
~S() { test |= bit; }
};
-static void doit ()
+static __attribute__ ((noinline)) void doit ()
{
try {
S four(4);
@@ -62,7 +64,6 @@ static void doit ()
try {
S one(1);
force_unwind ();
-
} catch(...) {
test |= 2;
throw;
Index: gcc/gcc/testsuite/g++.dg/eh/forced2.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced2.C 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced2.C 2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
#include <unwind.h>
#include <stdlib.h>
+#include <string.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
@@ -29,7 +30,8 @@ static void
force_unwind ()
{
_Unwind_Exception *exc = new _Unwind_Exception;
- exc->exception_class = 0;
+ // exception_class might not be a scalar.
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
exc->exception_cleanup = force_unwind_cleanup;
#ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/g++.dg/eh/forced3.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced3.C 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced3.C 2005-11-14 10:51:09.000000000 -0500
@@ -7,6 +7,7 @@
#include <unwind.h>
#include <stdlib.h>
#include <exception>
+#include <string.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
@@ -24,7 +25,8 @@ static void __attribute__((noreturn))
force_unwind ()
{
_Unwind_Exception *exc = new _Unwind_Exception;
- exc->exception_class = 0;
+ // exception_class might not be a scalar.
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
exc->exception_cleanup = 0;
#ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/gcc/testsuite/g++.dg/eh/forced4.C
===================================================================
--- gcc.orig/gcc/testsuite/g++.dg/eh/forced4.C 2005-11-14 10:34:09.000000000 -0500
+++ gcc/gcc/testsuite/g++.dg/eh/forced4.C 2005-11-14 10:51:09.000000000 -0500
@@ -6,6 +6,7 @@
#include <unwind.h>
#include <stdlib.h>
+#include <string.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
@@ -23,7 +24,8 @@ static void __attribute__((noreturn))
force_unwind ()
{
_Unwind_Exception *exc = new _Unwind_Exception;
- exc->exception_class = 0;
+ // exception_class might not be a scalar.
+ memset (&exc->exception_class, 0, sizeof (exc->exception_class));
exc->exception_cleanup = 0;
#ifndef __USING_SJLJ_EXCEPTIONS__
Index: gcc/libstdc++-v3/libsupc++/eh_arm.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_arm.cc 2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_arm.cc 2005-11-14 10:51:09.000000000 -0500
@@ -89,20 +89,31 @@ __cxa_begin_cleanup(_Unwind_Exception* u
{
__cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception *header = __get_exception_header_from_ue(ue_header);
+ bool native = __is_gxx_exception_class(header->unwindHeader.exception_class);
- if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
+
+ if (native)
{
- // TODO: cleanups with foreign exceptions.
- return false;
+ header->propagationCount++;
+ // Add it to the chain if this is the first time we've seen this
+ // exception.
+ if (header->propagationCount == 1)
+ {
+ header->nextPropagatingException = globals->propagatingExceptions;
+ globals->propagatingExceptions = header;
+ }
}
- header->propagationCount++;
- // Add it to the chain if this is the first time we've seen this exception.
- if (header->propagationCount == 1)
+ else
{
- header->nextPropagatingException = globals->propagatingExceptions;
+ // Remember the exception object, so end_cleanup can return it.
+ // These cannot be stacked, so we must abort if we already have
+ // a propagating exception.
+ if (globals->propagatingExceptions)
+ std::terminate ();
globals->propagatingExceptions = header;
}
- return true;
+
+ return !native;
}
// Do the work for __cxa_end_cleanup. Returns the currently propagating
@@ -119,13 +130,19 @@ __gnu_end_cleanup(void)
if (!header)
std::terminate();
- header->propagationCount--;
- if (header->propagationCount == 0)
+ if (__is_gxx_exception_class(header->unwindHeader.exception_class))
{
- // Remove exception from chain.
- globals->propagatingExceptions = header->nextPropagatingException;
- header->nextPropagatingException = NULL;
+ header->propagationCount--;
+ if (header->propagationCount == 0)
+ {
+ // Remove exception from chain.
+ globals->propagatingExceptions = header->nextPropagatingException;
+ header->nextPropagatingException = NULL;
+ }
}
+ else
+ globals->propagatingExceptions = NULL;
+
return &header->unwindHeader;
}
Index: gcc/libstdc++-v3/libsupc++/eh_personality.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_personality.cc 2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_personality.cc 2005-11-14 10:51:09.000000000 -0500
@@ -369,7 +369,7 @@ PERSONALITY_FUNCTION (int version,
#ifdef __ARM_EABI_UNWINDER__
_Unwind_Action actions;
- switch (state)
+ switch (state & _US_ACTION_MASK)
{
case _US_VIRTUAL_UNWIND_FRAME:
actions = _UA_SEARCH_PHASE;
@@ -377,7 +377,8 @@ PERSONALITY_FUNCTION (int version,
case _US_UNWIND_FRAME_STARTING:
actions = _UA_CLEANUP_PHASE;
- if (ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+ if (!(state & _US_FORCE_UNWIND)
+ && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
actions |= _UA_HANDLER_FRAME;
break;
@@ -388,6 +389,7 @@ PERSONALITY_FUNCTION (int version,
default:
abort();
}
+ actions |= state & _US_FORCE_UNWIND;
// We don't know which runtime we're working with, so can't check this.
// However the ABI routines hide this from us, and we don't actually need
@@ -523,13 +525,13 @@ PERSONALITY_FUNCTION (int version,
// exception class, there's no exception type.
// ??? What to do about GNU Java and GNU Ada exceptions.
-#ifdef __ARM_EABI_UNWINDER__
- throw_type = ue_header;
-#else
if ((actions & _UA_FORCE_UNWIND)
|| foreign_exception)
throw_type = 0;
else
+#ifdef __ARM_EABI_UNWINDER__
+ throw_type = ue_header;
+#else
throw_type = xh->exceptionType;
#endif
@@ -613,7 +615,6 @@ PERSONALITY_FUNCTION (int version,
install_context:
-#ifndef __ARM_EABI_UNWINDER__
// We can't use any of the cxa routines with foreign exceptions,
// because they all expect ue_header to be a struct __cxa_exception.
// So in that case, call terminate or unexpected directly.
@@ -631,7 +632,6 @@ PERSONALITY_FUNCTION (int version,
}
}
else
-#endif
{
if (found_type == found_terminate)
__cxa_call_terminate(ue_header);
Index: gcc/libstdc++-v3/libsupc++/eh_throw.cc
===================================================================
--- gcc.orig/libstdc++-v3/libsupc++/eh_throw.cc 2005-11-14 10:34:09.000000000 -0500
+++ gcc/libstdc++-v3/libsupc++/eh_throw.cc 2005-11-14 10:51:09.000000000 -0500
@@ -97,7 +97,7 @@ __cxxabiv1::__cxa_rethrow ()
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
_Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
#else
-#if defined(_LIBUNWIND_STD_ABI) || defined (__ARM_EABI_UNWINDER__)
+#if defined(_LIBUNWIND_STD_ABI)
_Unwind_RaiseException (&header->unwindHeader);
#else
_Unwind_Resume_or_Rethrow (&header->unwindHeader);