summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-16 11:52:55 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-16 11:52:55 +0000
commit31933f89f9d41a0e5af922951c334cbdb0a99596 (patch)
treeda08a4ceb1400ad593f6a055dc2999c204a77e07 /gcc
parent9fbc9c4d2c5f81941cf45da348627967f4852458 (diff)
downloadgcc-31933f89f9d41a0e5af922951c334cbdb0a99596.tar.gz
* unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
(uw_update_context_1): Use it. * config/rs6000/rs6000.c (insn_after_throw): Remove. (rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location in parent frame if _Unwind_* called directly instead of through .plt. (rs6000_emit_eh_toc_restore): Remove. (rs6000_emit_prologue): Update stack pointer before doing any saving if current_function_calls_eh_return. Generate unwind info for $r2. (rs6000_emit_epilogue): Restore stack pointer after doing all restoring if current_function_calls_eh_return. Restore $r2. * config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove. * config/rs6000/rs6000.md (eh_return): Remove call to rs6000_emit_eh_toc_restore. * config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define. * config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define. * gcc.dg/cleanup-8.c: New test. * gcc.dg/cleanup-9.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69450 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/config/rs6000/aix.h32
-rw-r--r--gcc/config/rs6000/linux64.h18
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c166
-rw-r--r--gcc/config/rs6000/rs6000.md2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/cleanup-8.c97
-rw-r--r--gcc/testsuite/gcc.dg/cleanup-9.c101
-rw-r--r--gcc/unwind-dw2.c7
10 files changed, 332 insertions, 116 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0e76adbcc02..027a53f7406 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2003-07-16 Jakub Jelinek <jakub@redhat.com>
+
+ * unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
+ (uw_update_context_1): Use it.
+ * config/rs6000/rs6000.c (insn_after_throw): Remove.
+ (rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location
+ in parent frame if _Unwind_* called directly instead of through
+ .plt.
+ (rs6000_emit_eh_toc_restore): Remove.
+ (rs6000_emit_prologue): Update stack pointer before doing any saving
+ if current_function_calls_eh_return. Generate unwind info for $r2.
+ (rs6000_emit_epilogue): Restore stack pointer after doing all
+ restoring if current_function_calls_eh_return. Restore $r2.
+ * config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove.
+ * config/rs6000/rs6000.md (eh_return): Remove call to
+ rs6000_emit_eh_toc_restore.
+ * config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define.
+ * config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define.
+
2003-07-15 Jakub Jelinek <jakub@redhat.com>
* expr.c (emit_block_move): Don't move anything if size is const 0.
diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h
index d40221513aa..ec6a350f157 100644
--- a/gcc/config/rs6000/aix.h
+++ b/gcc/config/rs6000/aix.h
@@ -209,6 +209,38 @@
So we have to squirrel it away with this. */
#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
+/* If the current unwind info (FS) does not contain explicit info
+ saving R2, then we have to do a minor amount of code reading to
+ figure out if it was saved. The big problem here is that the
+ code that does the save/restore is generated by the linker, so
+ we have no good way to determine at compile time what to do. */
+
+#ifdef __powerpc64__
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
+ do { \
+ if ((FS)->regs.reg[2].how == REG_UNSAVED) \
+ { \
+ unsigned int *insn \
+ = (unsigned int *) \
+ _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
+ if (*insn == 0xE8410028) \
+ _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
+ } \
+ } while (0)
+#else
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
+ do { \
+ if ((FS)->regs.reg[2].how == REG_UNSAVED) \
+ { \
+ unsigned int *insn \
+ = (unsigned int *) \
+ _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
+ if (*insn == 0x80410014) \
+ _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20); \
+ } \
+ } while (0)
+#endif
+
#define PROFILE_HOOK(LABEL) output_profile_hook (LABEL)
/* Print subsidiary information on the compiler version in use. */
diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h
index 4ef7382cee8..5d7c74df266 100644
--- a/gcc/config/rs6000/linux64.h
+++ b/gcc/config/rs6000/linux64.h
@@ -553,6 +553,24 @@ enum { SIGNAL_FRAMESIZE = 64 };
#ifdef __powerpc64__
+/* If the current unwind info (FS) does not contain explicit info
+ saving R2, then we have to do a minor amount of code reading to
+ figure out if it was saved. The big problem here is that the
+ code that does the save/restore is generated by the linker, so
+ we have no good way to determine at compile time what to do. */
+
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
+ do { \
+ if ((FS)->regs.reg[2].how == REG_UNSAVED) \
+ { \
+ unsigned int *insn \
+ = (unsigned int *) \
+ _Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
+ if (*insn == 0xE8410028) \
+ _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
+ } \
+ } while (0)
+
#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
do { \
unsigned char *pc_ = (CONTEXT)->ra; \
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index fc7e9cb96d8..bbdaa6ac6f0 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -126,7 +126,6 @@ extern int mfcr_operation PARAMS ((rtx, enum machine_mode));
extern int mtcrf_operation PARAMS ((rtx, enum machine_mode));
extern int lmw_operation PARAMS ((rtx, enum machine_mode));
extern struct rtx_def *create_TOC_reference PARAMS ((rtx));
-extern void rs6000_emit_eh_toc_restore PARAMS ((rtx));
extern void rs6000_split_altivec_in_gprs (rtx *);
extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index fa296d5db94..8f268974aa5 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -10800,132 +10800,40 @@ create_TOC_reference (symbol)
gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
}
-/* __throw will restore its own return address to be the same as the
- return address of the function that the throw is being made to.
- This is unfortunate, because we want to check the original
- return address to see if we need to restore the TOC.
- So we have to squirrel it away here.
- This is used only in compiling __throw and __rethrow.
+/* If _Unwind_* has been called from within the same module,
+ toc register is not guaranteed to be saved to 40(1) on function
+ entry. Save it there in that case. */
- Most of this code should be removed by CSE. */
-static rtx insn_after_throw;
-
-/* This does the saving... */
void
rs6000_aix_emit_builtin_unwind_init ()
{
rtx mem;
rtx stack_top = gen_reg_rtx (Pmode);
rtx opcode_addr = gen_reg_rtx (Pmode);
-
- insn_after_throw = gen_reg_rtx (SImode);
+ rtx opcode = gen_reg_rtx (SImode);
+ rtx tocompare = gen_reg_rtx (SImode);
+ rtx no_toc_save_needed = gen_label_rtx ();
mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
emit_move_insn (stack_top, mem);
- mem = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, stack_top,
+ mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode, stack_top,
GEN_INT (2 * GET_MODE_SIZE (Pmode))));
emit_move_insn (opcode_addr, mem);
- emit_move_insn (insn_after_throw, gen_rtx_MEM (SImode, opcode_addr));
-}
-
-/* Emit insns to _restore_ the TOC register, at runtime (specifically
- in _eh.o). Only used on AIX.
-
- The idea is that on AIX, function calls look like this:
- bl somefunction-trampoline
- lwz r2,20(sp)
-
- and later,
- somefunction-trampoline:
- stw r2,20(sp)
- ... load function address in the count register ...
- bctr
- or like this, if the linker determines that this is not a cross-module call
- and so the TOC need not be restored:
- bl somefunction
- nop
- or like this, if the compiler could determine that this is not a
- cross-module call:
- bl somefunction
- now, the tricky bit here is that register 2 is saved and restored
- by the _linker_, so we can't readily generate debugging information
- for it. So we need to go back up the call chain looking at the
- insns at return addresses to see which calls saved the TOC register
- and so see where it gets restored from.
-
- Oh, and all this gets done in RTL inside the eh_epilogue pattern,
- just before the actual epilogue.
-
- On the bright side, this incurs no space or time overhead unless an
- exception is thrown, except for the extra code in libgcc.a.
-
- The parameter STACKSIZE is a register containing (at runtime)
- the amount to be popped off the stack in addition to the stack frame
- of this routine (which will be __throw or __rethrow, and so is
- guaranteed to have a stack frame). */
-
-void
-rs6000_emit_eh_toc_restore (stacksize)
- rtx stacksize;
-{
- rtx top_of_stack;
- rtx bottom_of_stack = gen_reg_rtx (Pmode);
- rtx tocompare = gen_reg_rtx (SImode);
- rtx opcode = gen_reg_rtx (SImode);
- rtx opcode_addr = gen_reg_rtx (Pmode);
- rtx mem;
- rtx loop_start = gen_label_rtx ();
- rtx no_toc_restore_needed = gen_label_rtx ();
- rtx loop_exit = gen_label_rtx ();
-
- mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
- set_mem_alias_set (mem, rs6000_sr_alias_set);
- emit_move_insn (bottom_of_stack, mem);
-
- top_of_stack = expand_binop (Pmode, add_optab,
- bottom_of_stack, stacksize,
- NULL_RTX, 1, OPTAB_WIDEN);
-
- emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
+ emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
+ emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
: 0xE8410028, SImode));
- if (insn_after_throw == NULL_RTX)
- abort ();
- emit_move_insn (opcode, insn_after_throw);
-
- emit_note (NOTE_INSN_LOOP_BEG);
- emit_label (loop_start);
-
- do_compare_rtx_and_jump (opcode, tocompare, NE, 1,
+ do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
SImode, NULL_RTX, NULL_RTX,
- no_toc_restore_needed);
-
- mem = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, bottom_of_stack,
- GEN_INT (5 * GET_MODE_SIZE (Pmode))));
- emit_move_insn (gen_rtx_REG (Pmode, 2), mem);
-
- emit_label (no_toc_restore_needed);
- do_compare_rtx_and_jump (top_of_stack, bottom_of_stack, EQ, 1,
- Pmode, NULL_RTX, NULL_RTX,
- loop_exit);
-
- mem = gen_rtx_MEM (Pmode, bottom_of_stack);
- set_mem_alias_set (mem, rs6000_sr_alias_set);
- emit_move_insn (bottom_of_stack, mem);
-
- mem = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, bottom_of_stack,
- GEN_INT (2 * GET_MODE_SIZE (Pmode))));
- emit_move_insn (opcode_addr, mem);
- emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
+ no_toc_save_needed);
- emit_note (NOTE_INSN_LOOP_CONT);
- emit_jump (loop_start);
- emit_note (NOTE_INSN_LOOP_END);
- emit_label (loop_exit);
+ mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode, stack_top,
+ GEN_INT (5 * GET_MODE_SIZE (Pmode))));
+ emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
+ emit_label (no_toc_save_needed);
}
/* This ties together stack memory (MEM with an alias set of
@@ -11347,7 +11255,8 @@ rs6000_emit_prologue ()
|| FP_SAVE_INLINE (info->first_fp_reg_save));
/* For V.4, update stack before we do any saving and set back pointer. */
- if (info->push_p && DEFAULT_ABI == ABI_V4)
+ if (info->push_p
+ && (DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
{
if (info->total_size < 32767)
sp_offset = info->total_size;
@@ -11575,6 +11484,23 @@ rs6000_emit_prologue ()
{
unsigned int i, regno;
+ /* In AIX ABI we need to pretend we save r2 here. */
+ if (TARGET_AIX)
+ {
+ rtx addr, reg, mem;
+
+ reg = gen_rtx_REG (reg_mode, 2);
+ addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (sp_offset + 5 * reg_size));
+ mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ insn = emit_move_insn (mem, reg);
+ rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ NULL_RTX, NULL_RTX);
+ PATTERN (insn) = gen_blockage ();
+ }
+
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
@@ -11633,7 +11559,8 @@ rs6000_emit_prologue ()
/* Update stack and set back pointer unless this is V.4,
for which it was done previously. */
- if (info->push_p && DEFAULT_ABI != ABI_V4)
+ if (info->push_p
+ && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
rs6000_emit_allocate_stack (info->total_size, FALSE);
/* Set frame pointer, if needed. */
@@ -11812,7 +11739,8 @@ rs6000_emit_epilogue (sibcall)
}
else if (info->push_p)
{
- if (DEFAULT_ABI == ABI_V4)
+ if (DEFAULT_ABI == ABI_V4
+ || current_function_calls_eh_return)
sp_offset = info->total_size;
else
{
@@ -11897,6 +11825,17 @@ rs6000_emit_epilogue (sibcall)
{
unsigned int i, regno;
+ if (TARGET_AIX)
+ {
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (sp_offset + 5 * reg_size));
+ rtx mem = gen_rtx_MEM (reg_mode, addr);
+
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
+ }
+
for (i = 0; ; ++i)
{
rtx mem;
@@ -12048,7 +11987,8 @@ rs6000_emit_epilogue (sibcall)
(which may not have any obvious dependency on the stack). This
doesn't hurt performance, because there is no scheduling that can
be done after this point. */
- if (DEFAULT_ABI == ABI_V4)
+ if (DEFAULT_ABI == ABI_V4
+ || current_function_calls_eh_return)
{
if (frame_reg_rtx != sp_reg_rtx)
rs6000_emit_stack_tie ();
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index bf778e2e22c..f39e849628a 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -14637,8 +14637,6 @@
""
"
{
- if (TARGET_AIX)
- rs6000_emit_eh_toc_restore (EH_RETURN_STACKADJ_RTX);
if (TARGET_32BIT)
emit_insn (gen_eh_set_lr_si (operands[0]));
else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e6f3233c9ff..ab2deeb4fe6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2003-07-16 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/cleanup-8.c: New test.
+ * gcc.dg/cleanup-9.c: New test.
+
2003-07-16 Danny Smith <dannysmith@users.sourceforge.net>
* g++.dg/ext/dll-MI1.h: New file.
diff --git a/gcc/testsuite/gcc.dg/cleanup-8.c b/gcc/testsuite/gcc.dg/cleanup-8.c
new file mode 100644
index 00000000000..91e387ce799
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cleanup-8.c
@@ -0,0 +1,97 @@
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
+/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
+/* Verify that cleanups work with exception handling through signal
+ frames. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc = malloc (sizeof (*exc));
+ exc->exception_class = 0;
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ signal (SIGSEGV, fn4);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-9.c b/gcc/testsuite/gcc.dg/cleanup-9.c
new file mode 100644
index 00000000000..0c17f25f63d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cleanup-9.c
@@ -0,0 +1,101 @@
+/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
+/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
+/* Verify that cleanups work with exception handling through realtime
+ signal frames. */
+
+#include <unwind.h>
+#include <stdlib.h>
+#include <signal.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+ _Unwind_Exception_Class exc_class,
+ struct _Unwind_Exception *exc_obj,
+ struct _Unwind_Context *context,
+ void *stop_parameter)
+{
+ if (actions & _UA_END_OF_STACK)
+ abort ();
+ return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+ struct _Unwind_Exception *exc = malloc (sizeof (*exc));
+ exc->exception_class = 0;
+ exc->exception_cleanup = 0;
+
+#ifndef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+ _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+
+ abort ();
+}
+
+int count;
+char *null;
+
+static void counter (void *p __attribute__((unused)))
+{
+ ++count;
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+ if (count != 2)
+ abort ();
+ exit (0);
+}
+
+static int __attribute__((noinline)) fn5 ()
+{
+ char dummy __attribute__((cleanup (counter)));
+ force_unwind ();
+ return 0;
+}
+
+static void fn4 (int sig, siginfo_t *info, void *ctx)
+{
+ char dummy __attribute__((cleanup (counter)));
+ fn5 ();
+ null = NULL;
+}
+
+static void fn3 ()
+{
+ abort ();
+}
+
+static int __attribute__((noinline)) fn2 ()
+{
+ *null = 0;
+ fn3 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn1 ()
+{
+ struct sigaction s;
+ sigemptyset (&s.sa_mask);
+ s.sa_sigaction = fn4;
+ s.sa_flags = SA_ONESHOT | SA_SIGINFO;
+ sigaction (SIGSEGV, &s, NULL);
+ fn2 ();
+ return 0;
+}
+
+static int __attribute__((noinline)) fn0 ()
+{
+ char dummy __attribute__((cleanup (handler)));
+ fn1 ();
+ null = 0;
+ return 0;
+}
+
+int main()
+{
+ fn0 ();
+ abort ();
+}
diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c
index eadd88bba5a..3e58be6cb69 100644
--- a/gcc/unwind-dw2.c
+++ b/gcc/unwind-dw2.c
@@ -54,6 +54,11 @@
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
#endif
+/* A target can do some update context frobbing. */
+#ifndef MD_FROB_UPDATE_CONTEXT
+#define MD_FROB_UPDATE_CONTEXT(CTX, FS) do { } while (0)
+#endif
+
/* This is the register and unwind state for a particular frame. This
provides the information necessary to unwind up past a frame and return
to its caller. */
@@ -1203,6 +1208,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
}
break;
}
+
+ MD_FROB_UPDATE_CONTEXT (context, fs);
}
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE