unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
* 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. From-SVN: r69450
This commit is contained in:
parent
6972c506d4
commit
fc4767bbb6
|
@ -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>
|
2003-07-15 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
* expr.c (emit_block_move): Don't move anything if size is const 0.
|
* expr.c (emit_block_move): Don't move anything if size is const 0.
|
||||||
|
|
|
@ -209,6 +209,38 @@
|
||||||
So we have to squirrel it away with this. */
|
So we have to squirrel it away with this. */
|
||||||
#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
|
#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)
|
#define PROFILE_HOOK(LABEL) output_profile_hook (LABEL)
|
||||||
|
|
||||||
/* Print subsidiary information on the compiler version in use. */
|
/* Print subsidiary information on the compiler version in use. */
|
||||||
|
|
|
@ -553,6 +553,24 @@ enum { SIGNAL_FRAMESIZE = 64 };
|
||||||
|
|
||||||
#ifdef __powerpc64__
|
#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) \
|
#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
|
||||||
do { \
|
do { \
|
||||||
unsigned char *pc_ = (CONTEXT)->ra; \
|
unsigned char *pc_ = (CONTEXT)->ra; \
|
||||||
|
|
|
@ -126,7 +126,6 @@ extern int mfcr_operation PARAMS ((rtx, enum machine_mode));
|
||||||
extern int mtcrf_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 int lmw_operation PARAMS ((rtx, enum machine_mode));
|
||||||
extern struct rtx_def *create_TOC_reference PARAMS ((rtx));
|
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_split_altivec_in_gprs (rtx *);
|
||||||
extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
|
extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
|
||||||
extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
|
extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));
|
||||||
|
|
|
@ -10800,132 +10800,40 @@ create_TOC_reference (symbol)
|
||||||
gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
|
gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* __throw will restore its own return address to be the same as the
|
/* If _Unwind_* has been called from within the same module,
|
||||||
return address of the function that the throw is being made to.
|
toc register is not guaranteed to be saved to 40(1) on function
|
||||||
This is unfortunate, because we want to check the original
|
entry. Save it there in that case. */
|
||||||
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.
|
|
||||||
|
|
||||||
Most of this code should be removed by CSE. */
|
|
||||||
static rtx insn_after_throw;
|
|
||||||
|
|
||||||
/* This does the saving... */
|
|
||||||
void
|
void
|
||||||
rs6000_aix_emit_builtin_unwind_init ()
|
rs6000_aix_emit_builtin_unwind_init ()
|
||||||
{
|
{
|
||||||
rtx mem;
|
rtx mem;
|
||||||
rtx stack_top = gen_reg_rtx (Pmode);
|
rtx stack_top = gen_reg_rtx (Pmode);
|
||||||
rtx opcode_addr = gen_reg_rtx (Pmode);
|
rtx opcode_addr = gen_reg_rtx (Pmode);
|
||||||
|
rtx opcode = gen_reg_rtx (SImode);
|
||||||
insn_after_throw = 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);
|
mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
|
||||||
emit_move_insn (stack_top, mem);
|
emit_move_insn (stack_top, mem);
|
||||||
|
|
||||||
mem = gen_rtx_MEM (Pmode,
|
mem = gen_rtx_MEM (Pmode,
|
||||||
gen_rtx_PLUS (Pmode, stack_top,
|
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
|
|
||||||
: 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,
|
|
||||||
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))));
|
GEN_INT (2 * GET_MODE_SIZE (Pmode))));
|
||||||
emit_move_insn (opcode_addr, mem);
|
emit_move_insn (opcode_addr, mem);
|
||||||
emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
|
emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
|
||||||
|
emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
|
||||||
|
: 0xE8410028, SImode));
|
||||||
|
|
||||||
emit_note (NOTE_INSN_LOOP_CONT);
|
do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
|
||||||
emit_jump (loop_start);
|
SImode, NULL_RTX, NULL_RTX,
|
||||||
emit_note (NOTE_INSN_LOOP_END);
|
no_toc_save_needed);
|
||||||
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
|
/* 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));
|
|| FP_SAVE_INLINE (info->first_fp_reg_save));
|
||||||
|
|
||||||
/* For V.4, update stack before we do any saving and set back pointer. */
|
/* 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)
|
if (info->total_size < 32767)
|
||||||
sp_offset = info->total_size;
|
sp_offset = info->total_size;
|
||||||
|
@ -11575,6 +11484,23 @@ rs6000_emit_prologue ()
|
||||||
{
|
{
|
||||||
unsigned int i, regno;
|
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)
|
for (i = 0; ; ++i)
|
||||||
{
|
{
|
||||||
regno = EH_RETURN_DATA_REGNO (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,
|
/* Update stack and set back pointer unless this is V.4,
|
||||||
for which it was done previously. */
|
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);
|
rs6000_emit_allocate_stack (info->total_size, FALSE);
|
||||||
|
|
||||||
/* Set frame pointer, if needed. */
|
/* Set frame pointer, if needed. */
|
||||||
|
@ -11812,7 +11739,8 @@ rs6000_emit_epilogue (sibcall)
|
||||||
}
|
}
|
||||||
else if (info->push_p)
|
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;
|
sp_offset = info->total_size;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -11897,6 +11825,17 @@ rs6000_emit_epilogue (sibcall)
|
||||||
{
|
{
|
||||||
unsigned int i, regno;
|
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)
|
for (i = 0; ; ++i)
|
||||||
{
|
{
|
||||||
rtx mem;
|
rtx mem;
|
||||||
|
@ -12048,7 +11987,8 @@ rs6000_emit_epilogue (sibcall)
|
||||||
(which may not have any obvious dependency on the stack). This
|
(which may not have any obvious dependency on the stack). This
|
||||||
doesn't hurt performance, because there is no scheduling that can
|
doesn't hurt performance, because there is no scheduling that can
|
||||||
be done after this point. */
|
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)
|
if (frame_reg_rtx != sp_reg_rtx)
|
||||||
rs6000_emit_stack_tie ();
|
rs6000_emit_stack_tie ();
|
||||||
|
|
|
@ -14637,8 +14637,6 @@
|
||||||
""
|
""
|
||||||
"
|
"
|
||||||
{
|
{
|
||||||
if (TARGET_AIX)
|
|
||||||
rs6000_emit_eh_toc_restore (EH_RETURN_STACKADJ_RTX);
|
|
||||||
if (TARGET_32BIT)
|
if (TARGET_32BIT)
|
||||||
emit_insn (gen_eh_set_lr_si (operands[0]));
|
emit_insn (gen_eh_set_lr_si (operands[0]));
|
||||||
else
|
else
|
||||||
|
|
|
@ -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>
|
2003-07-16 Danny Smith <dannysmith@users.sourceforge.net>
|
||||||
|
|
||||||
* g++.dg/ext/dll-MI1.h: New file.
|
* g++.dg/ext/dll-MI1.h: New file.
|
||||||
|
|
|
@ -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 ();
|
||||||
|
}
|
|
@ -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 ();
|
||||||
|
}
|
|
@ -54,6 +54,11 @@
|
||||||
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
|
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
|
||||||
#endif
|
#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
|
/* This is the register and unwind state for a particular frame. This
|
||||||
provides the information necessary to unwind up past a frame and return
|
provides the information necessary to unwind up past a frame and return
|
||||||
to its caller. */
|
to its caller. */
|
||||||
|
@ -1203,6 +1208,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MD_FROB_UPDATE_CONTEXT (context, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
|
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE
|
||||||
|
|
Loading…
Reference in New Issue