diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fc2546b49389..e2b09d7819f7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2003-09-30 Richard Henderson + + * dwarf2out.c (expand_builtin_init_dwarf_reg_sizes): Honor + DWARF_ALT_FRAME_RETURN_COLUMN. + * unwind-dw2.c (dwarf_reg_size_table): Expand by one. + (_Unwind_GetGR, _Unwind_SetGR): Validate lookup column. + (uw_frame_state_for): Return end-of-stack for null return address. + * doc/tm.texi (DWARF_ALT_FRAME_RETURN_COLUMN): Add. + + * config/alpha/alpha.c (alpha_sa_mask): Add r31 for eh_return. + (alpha_expand_prologue): Store a zero for it. + (alpha_expand_epilogue): Don't reload it. + * config/alpha/alpha.h (DWARF_ALT_FRAME_RETURN_COLUMN): New. + * config/alpha/linux.h (MD_FALLBACK_FRAME_STATE_FOR): Use column 64 + for the sigframe return address. + 2003-09-30 Kelley Cook * sdbout.c: Convert to ISO C90 prototypes. diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 18b2d53667e5..ad6b61977e29 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -6700,13 +6700,20 @@ alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP) /* We need to restore these for the handler. */ if (current_function_calls_eh_return) - for (i = 0; ; ++i) - { - unsigned regno = EH_RETURN_DATA_REGNO (i); - if (regno == INVALID_REGNUM) - break; - imask |= 1UL << regno; - } + { + for (i = 0; ; ++i) + { + unsigned regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + imask |= 1UL << regno; + } + + /* Glibc likes to use $31 as an unwind stopper for crt0. To + avoid hackery in unwind-dw2.c, we need to actively store a + zero in the prologue of _Unwind_RaiseException et al. */ + imask |= 1UL << 31; + } /* If any register spilled, then spill the return address also. */ /* ??? This is required by the Digital stack unwind specification @@ -7168,7 +7175,7 @@ alpha_expand_prologue (void) } /* Now save any other registers required to be saved. */ - for (i = 0; i < 32; i++) + for (i = 0; i < 31; i++) if (imask & (1UL << i)) { mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); @@ -7177,7 +7184,25 @@ alpha_expand_prologue (void) reg_offset += 8; } - for (i = 0; i < 32; i++) + /* Store a zero if requested for unwinding. */ + if (imask & (1UL << 31)) + { + rtx insn, t; + + mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); + set_mem_alias_set (mem, alpha_sr_alias_set); + insn = emit_move_insn (mem, const0_rtx); + + RTX_FRAME_RELATED_P (insn) = 1; + t = gen_rtx_REG (Pmode, 31); + t = gen_rtx_SET (VOIDmode, mem, t); + t = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, t, REG_NOTES (insn)); + REG_NOTES (insn) = t; + + reg_offset += 8; + } + + for (i = 0; i < 31; i++) if (fmask & (1UL << i)) { mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset)); @@ -7588,7 +7613,7 @@ alpha_expand_epilogue (void) reg_offset += 8; imask &= ~(1UL << REG_RA); - for (i = 0; i < 32; ++i) + for (i = 0; i < 31; ++i) if (imask & (1UL << i)) { if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer) @@ -7602,7 +7627,10 @@ alpha_expand_epilogue (void) reg_offset += 8; } - for (i = 0; i < 32; ++i) + if (imask & (1UL << 31)) + reg_offset += 8; + + for (i = 0; i < 31; ++i) if (fmask & (1UL << i)) { mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset)); diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index e68cb4848e6a..5faadfbdbf04 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -1208,6 +1208,7 @@ do { \ /* Before the prologue, RA lives in $26. */ #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 26) #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (26) +#define DWARF_ALT_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (64) /* Describe how we implement __builtin_eh_return. */ #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 16 : INVALID_REGNUM) diff --git a/gcc/config/alpha/linux.h b/gcc/config/alpha/linux.h index 0853369171d4..2c9cc8ea6a1a 100644 --- a/gcc/config/alpha/linux.h +++ b/gcc/config/alpha/linux.h @@ -85,6 +85,8 @@ Boston, MA 02111-1307, USA. */ if (pc_[0] != 0x47fe0410 /* mov $30,$16 */ \ || pc_[2] != 0x00000083 /* callsys */) \ break; \ + if ((CONTEXT)->cfa == 0) \ + break; \ if (pc_[1] == 0x201f0067) /* lda $0,NR_sigreturn */ \ sc_ = (CONTEXT)->cfa; \ else if (pc_[1] == 0x201f015f) /* lda $0,NR_rt_sigreturn */ \ @@ -113,8 +115,8 @@ Boston, MA 02111-1307, USA. */ (FS)->regs.reg[i_+32].loc.offset \ = (long)&sc_->sc_fpregs[i_] - new_cfa_; \ } \ - (FS)->regs.reg[31].how = REG_SAVED_OFFSET; \ - (FS)->regs.reg[31].loc.offset = (long)&sc_->sc_pc - new_cfa_; \ - (FS)->retaddr_column = 31; \ + (FS)->regs.reg[64].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[64].loc.offset = (long)&sc_->sc_pc - new_cfa_; \ + (FS)->retaddr_column = 64; \ goto SUCCESS; \ } while (0) diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 582953b7bb5a..1e9a45c75869 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -2904,6 +2904,14 @@ If this RTL is a @code{REG}, you should also define @code{DWARF_FRAME_RETURN_COLUMN} to @code{DWARF_FRAME_REGNUM (REGNO)}. @end defmac +@defmac DWARF_ALT_FRAME_RETURN_COLUMN +A C expression whose value is an integer giving a DWARF 2 column +number that may be used as an alternate return column. This should +be defined only if @code{DWARF_FRAME_RETURN_COLUMN} is set to a +general register, but an alternate column needs to be used for +signal frames. +@end defmac + @defmac INCOMING_FRAME_SP_OFFSET A C expression whose value is an integer giving the offset, in bytes, from the value of the stack pointer register to the top of the stack diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index f22ca5045fd7..9a23c76b79ee 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -482,10 +482,20 @@ expand_builtin_init_dwarf_reg_sizes (tree address) emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size)); } + +#ifdef DWARF_ALT_FRAME_RETURN_COLUMN + if (! wrote_return_column) + abort (); + i = DWARF_ALT_FRAME_RETURN_COLUMN; + wrote_return_column = false; +#else + i = DWARF_FRAME_RETURN_COLUMN; +#endif + if (! wrote_return_column) { enum machine_mode save_mode = Pmode; - HOST_WIDE_INT offset = DWARF_FRAME_RETURN_COLUMN * GET_MODE_SIZE (mode); + HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode); HOST_WIDE_INT size = GET_MODE_SIZE (save_mode); emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size)); } diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index f94eaf99da9c..09396c807546 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -82,7 +82,7 @@ struct _Unwind_Context }; /* Byte size of every register managed by these routines. */ -static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS]; +static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1]; /* The result of interpreting the frame unwind info for a frame. @@ -186,6 +186,8 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index) void *ptr; index = DWARF_REG_TO_UNWIND_COLUMN (index); + if (index >= sizeof(dwarf_reg_size_table)) + abort (); size = dwarf_reg_size_table[index]; ptr = context->reg[index]; @@ -222,6 +224,8 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) void *ptr; index = DWARF_REG_TO_UNWIND_COLUMN (index); + if (index >= sizeof(dwarf_reg_size_table)) + abort (); size = dwarf_reg_size_table[index]; ptr = context->reg[index]; @@ -1002,6 +1006,9 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) context->args_size = 0; context->lsda = 0; + if (context->ra == 0) + return _URC_END_OF_STACK; + fde = _Unwind_Find_FDE (context->ra - 1, &context->bases); if (fde == NULL) {