mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-08 18:17:30 +08:00
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>
|
||||
|
||||
* 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. */
|
||||
#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. */
|
||||
|
@ -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; \
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
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,
|
||||
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 (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);
|
||||
emit_jump (loop_start);
|
||||
emit_note (NOTE_INSN_LOOP_END);
|
||||
emit_label (loop_exit);
|
||||
do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
|
||||
SImode, NULL_RTX, NULL_RTX,
|
||||
no_toc_save_needed);
|
||||
|
||||
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 ();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
97
gcc/testsuite/gcc.dg/cleanup-8.c
Normal file
97
gcc/testsuite/gcc.dg/cleanup-8.c
Normal 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 ();
|
||||
}
|
101
gcc/testsuite/gcc.dg/cleanup-9.c
Normal file
101
gcc/testsuite/gcc.dg/cleanup-9.c
Normal file
@ -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)
|
||||
#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
|
||||
|
Loading…
Reference in New Issue
Block a user