@@ -1290,3 +1290,8 @@ do { \
/* The system headers under Alpha systems are generally C++-aware. */
#define NO_IMPLICIT_EXTERN_C
+
+/* Bits 0 and 1 are always zero in jump targets. */
+#ifdef IN_LIBGCC2
+# define UNWIND_FORCE_UNWIND_MASK 1
+#endif
@@ -2920,3 +2920,15 @@ extern GTY(()) struct target_globals *mips16_globals;
with arguments ARGS. */
#define PMODE_INSN(NAME, ARGS) \
(Pmode == SImode ? NAME ## _si ARGS : NAME ## _di ARGS)
+
+/* For mips32 mode we have bits 0 and 1 zero free, but for mips16 mode,
+ bit 0 indicates mips16 mode, and bit 1 is thence meaningful. Thus
+ the only "free" bits would be at the top of the address space.
+ Can we trust that we'll never try to unwind in kernel mode? */
+#ifdef IN_LIBGCC2
+# if TARGET_64BIT
+# define UNWIND_FORCE_UNWIND_MASK 0x8000000000000000ull
+# else
+# define UNWIND_FORCE_UNWIND_MASK 0x80000000u
+# endif
+#endif
@@ -322,6 +322,9 @@ uw_identify_context (struct _Unwind_Context *context)
#define _Unwind_Resume _Unwind_SjLj_Resume
#define _Unwind_Resume_or_Rethrow _Unwind_SjLj_Resume_or_Rethrow
+/* Always use uw_identify_context to identify frames. */
+#undef UNWIND_FORCE_UNWIND_MASK
+
#include "unwind.inc"
#endif /* USING_SJLJ_EXCEPTIONS */
@@ -1,5 +1,5 @@
/* Exception handling and frame unwind runtime interface routines. -*- C -*-
- Copyright (C) 2001, 2003, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2003, 2008, 2009, 2012 Free Software Foundation, Inc.
This file is part of GCC.
@@ -27,6 +27,64 @@
This file is included from unwind-dw2.c, unwind-sjlj.c or
unwind-ia64.c. */
+/* This is a bit value within a function pointer or function return address
+ that is never set. E.g. most RISC targets have instructions aligned to
+ four bytes, meaning bits 0 and 1 are "free" and thus either 1 or 2 would
+ be appropriate values to use here.
+
+ If non-zero, we will use this bit to distinguish forced unwind from normal
+ unwind, and in addition use both the IP+CFA to identify the target context
+ during unwinding.
+
+ If zero, i.e. there is no "free" bit, then we will only be able to use the
+ CFA to identify the target context during unwinding. The consequence of
+ this is that we cannot reliably propagate an exception through a sequence
+ of functions that do not have a stack frame. Normally this is not a
+ problem, in that most functions that do not have stack frames are leaf
+ functions, and thus do not throw exceptions. */
+
+#include <stdbool.h>
+
+#ifndef UNWIND_FORCE_UNWIND_MASK
+# define UNWIND_FORCE_UNWIND_MASK 0
+#endif
+
+static inline bool
+is_forced_unwind (struct _Unwind_Exception *exc)
+{
+ if (UNWIND_FORCE_UNWIND_MASK != 0)
+ return (exc->private_1 & UNWIND_FORCE_UNWIND_MASK) != 0;
+ else
+ return exc->private_1 != 0;
+}
+
+static inline bool
+is_handler_match (struct _Unwind_Exception *exc,
+ struct _Unwind_Context *context)
+{
+ if (UNWIND_FORCE_UNWIND_MASK != 0)
+ return (_Unwind_GetIP (context) == exc->private_1
+ && _Unwind_GetCFA (context) == exc->private_2);
+ else
+ return uw_identify_context (context) == exc->private_2;
+}
+
+static inline void
+record_handler_match (struct _Unwind_Exception *exc,
+ struct _Unwind_Context *context)
+{
+ if (UNWIND_FORCE_UNWIND_MASK != 0)
+ {
+ exc->private_1 = _Unwind_GetIP (context);
+ exc->private_2 = _Unwind_GetCFA (context);
+ }
+ else
+ {
+ exc->private_1 = 0;
+ exc->private_2 = uw_identify_context (context);
+ }
+}
+
/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume.
Unwind the stack calling the personality routine to find both the
@@ -48,8 +106,7 @@ _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc,
code = uw_frame_state_for (context, &fs);
/* Identify when we've reached the designated handler context. */
- match_handler = (uw_identify_context (context) == exc->private_2
- ? _UA_HANDLER_FRAME : 0);
+ match_handler = is_handler_match (exc, context) ? _UA_HANDLER_FRAME : 0;
if (code != _URC_NO_REASON)
/* Some error encountered. Usually the unwinder doesn't
@@ -124,8 +181,7 @@ _Unwind_RaiseException(struct _Unwind_Exception *exc)
/* Indicate to _Unwind_Resume and associated subroutines that this
is not a forced unwind. Further, note where we found a handler. */
- exc->private_1 = 0;
- exc->private_2 = uw_identify_context (&cur_context);
+ record_handler_match (exc, &cur_context);
cur_context = this_context;
code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
@@ -142,7 +198,8 @@ static _Unwind_Reason_Code
_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc,
struct _Unwind_Context *context)
{
- _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1;
+ _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn)
+ (_Unwind_Ptr) (exc->private_1 & ~UNWIND_FORCE_UNWIND_MASK);
void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2;
_Unwind_Reason_Code code, stop_code;
@@ -201,7 +258,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
uw_init_context (&this_context);
cur_context = this_context;
- exc->private_1 = (_Unwind_Ptr) stop;
+ exc->private_1 = (_Unwind_Ptr) stop | UNWIND_FORCE_UNWIND_MASK;
exc->private_2 = (_Unwind_Ptr) stop_argument;
code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
@@ -226,10 +283,10 @@ _Unwind_Resume (struct _Unwind_Exception *exc)
/* Choose between continuing to process _Unwind_RaiseException
or _Unwind_ForcedUnwind. */
- if (exc->private_1 == 0)
- code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
- else
+ if (is_forced_unwind (exc))
code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
+ else
+ code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
gcc_assert (code == _URC_INSTALL_CONTEXT);
@@ -248,7 +305,7 @@ _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc)
/* Choose between continuing to process _Unwind_RaiseException
or _Unwind_ForcedUnwind. */
- if (exc->private_1 == 0)
+ if (!is_forced_unwind (exc))
return _Unwind_RaiseException (exc);
uw_init_context (&this_context);