This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fix alpha signal unwind with new glibc


Blah.  I think I tested this glibc unwind change only with gdb, and
didn't notice the gcc regressions.  This change is now in Debian Testing,
and I only noticed when trying to fix all tree-ssa failures.  I guess
in spite of having to hack up gcc to match, I still think the glibc
change was a good idea.

Problem 1: _start uses r31 for both the outer cfa and the return address.
The architecture r31 is the zero register.  Except that the unwinder 
doesn't know that.  All it sees is that r31 hasn't been saved, so we 
segfault.

Fixed by having the eh_return frame store a zero with r31's name on it.

Problem 2: libc's signal return trampoline uses r64 for the return address
from the signal frame.  (Yes, MD_FALLBACK_FRAME_STATE_FOR is not used
on a sufficiently new glibc.  Yeah!)  Except that (a) dwarf_reg_size_table
wasn't that large and (b) we need to initialize it, somehow.

Fixed by adding DWARF_ALT_FRAME_RETURN_COLUMN, and expanding
dwarf_reg_size_table to match the size of _Unwind_Context.reg.

I guess I'll apply this to 3.3 branch as well...


r~


        * 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.

Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.455
diff -c -p -d -r1.455 dwarf2out.c
*** dwarf2out.c	29 Sep 2003 22:07:38 -0000	1.455
--- dwarf2out.c	1 Oct 2003 05:50:15 -0000
*************** expand_builtin_init_dwarf_reg_sizes (tre
*** 482,491 ****
  
  	emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
        }
    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 size = GET_MODE_SIZE (save_mode);
        emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
      }
--- 482,501 ----
  
  	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 = 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));
      }
Index: unwind-dw2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/unwind-dw2.c,v
retrieving revision 1.35
diff -c -p -d -r1.35 unwind-dw2.c
*** unwind-dw2.c	19 Aug 2003 20:53:24 -0000	1.35
--- unwind-dw2.c	1 Oct 2003 05:50:16 -0000
*************** struct _Unwind_Context
*** 82,88 ****
  };
  
  /* Byte size of every register managed by these routines.  */
! static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
  
  
  /* The result of interpreting the frame unwind info for a frame.
--- 82,88 ----
  };
  
  /* Byte size of every register managed by these routines.  */
! static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
  
  
  /* The result of interpreting the frame unwind info for a frame.
*************** _Unwind_GetGR (struct _Unwind_Context *c
*** 186,191 ****
--- 186,193 ----
    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];
  
*************** _Unwind_SetGR (struct _Unwind_Context *c
*** 222,227 ****
--- 224,231 ----
    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];
  
*************** uw_frame_state_for (struct _Unwind_Conte
*** 1001,1006 ****
--- 1005,1013 ----
    memset (fs, 0, sizeof (*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)
Index: config/alpha/alpha.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v
retrieving revision 1.327
diff -c -p -d -r1.327 alpha.c
*** config/alpha/alpha.c	27 Sep 2003 04:48:12 -0000	1.327
--- config/alpha/alpha.c	1 Oct 2003 05:50:24 -0000
*************** alpha_sa_mask (unsigned long *imaskP, un
*** 6700,6712 ****
  
    /* 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;
!       }
       
    /* If any register spilled, then spill the return address also.  */
    /* ??? This is required by the Digital stack unwind specification
--- 6700,6719 ----
  
    /* 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;
! 	}
! 
!       /* 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
*************** alpha_expand_prologue (void)
*** 7168,7174 ****
  	}
  
        /* Now save any other registers required to be saved.  */
!       for (i = 0; i < 32; i++)
  	if (imask & (1UL << i))
  	  {
  	    mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
--- 7175,7181 ----
  	}
  
        /* Now save any other registers required to be saved.  */
!       for (i = 0; i < 31; i++)
  	if (imask & (1UL << i))
  	  {
  	    mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
*************** alpha_expand_prologue (void)
*** 7177,7183 ****
  	    reg_offset += 8;
  	  }
  
!       for (i = 0; i < 32; i++)
  	if (fmask & (1UL << i))
  	  {
  	    mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
--- 7184,7208 ----
  	    reg_offset += 8;
  	  }
  
!       /* 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));
*************** alpha_expand_epilogue (void)
*** 7588,7594 ****
        reg_offset += 8;
        imask &= ~(1UL << REG_RA);
  
!       for (i = 0; i < 32; ++i)
  	if (imask & (1UL << i))
  	  {
  	    if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer)
--- 7613,7619 ----
        reg_offset += 8;
        imask &= ~(1UL << REG_RA);
  
!       for (i = 0; i < 31; ++i)
  	if (imask & (1UL << i))
  	  {
  	    if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer)
*************** alpha_expand_epilogue (void)
*** 7602,7608 ****
  	    reg_offset += 8;
  	  }
  
!       for (i = 0; i < 32; ++i)
  	if (fmask & (1UL << i))
  	  {
  	    mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset));
--- 7627,7636 ----
  	    reg_offset += 8;
  	  }
  
!       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));
Index: config/alpha/alpha.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.h,v
retrieving revision 1.205
diff -c -p -d -r1.205 alpha.h
*** config/alpha/alpha.h	27 Sep 2003 04:48:12 -0000	1.205
--- config/alpha/alpha.h	1 Oct 2003 05:50:26 -0000
*************** do {						\
*** 1208,1213 ****
--- 1208,1214 ----
  /* 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)
Index: config/alpha/linux.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/linux.h,v
retrieving revision 1.37
diff -c -p -d -r1.37 linux.h
*** config/alpha/linux.h	27 Sep 2003 04:48:12 -0000	1.37
--- config/alpha/linux.h	1 Oct 2003 05:50:26 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 85,90 ****
--- 85,92 ----
      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 */	\
*************** Boston, MA 02111-1307, USA.  */
*** 113,120 ****
  	(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;						\
      goto SUCCESS;							\
    } while (0)
--- 115,122 ----
  	(FS)->regs.reg[i_+32].loc.offset				\
  	  = (long)&sc_->sc_fpregs[i_] - new_cfa_;			\
        }									\
!     (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)
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.256
diff -c -p -d -r1.256 tm.texi
*** doc/tm.texi	23 Sep 2003 19:17:49 -0000	1.256
--- doc/tm.texi	1 Oct 2003 05:50:37 -0000
*************** If this RTL is a @code{REG}, you should 
*** 2904,2909 ****
--- 2904,2917 ----
  @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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]