163d1a8abSmrg /* DWARF2 EH unwinding support for Alpha Linux.
2*ec02198aSmrg    Copyright (C) 2004-2020 Free Software Foundation, Inc.
363d1a8abSmrg 
463d1a8abSmrg This file is part of GCC.
563d1a8abSmrg 
663d1a8abSmrg GCC is free software; you can redistribute it and/or modify
763d1a8abSmrg it under the terms of the GNU General Public License as published by
863d1a8abSmrg the Free Software Foundation; either version 3, or (at your option)
963d1a8abSmrg any later version.
1063d1a8abSmrg 
1163d1a8abSmrg GCC is distributed in the hope that it will be useful,
1263d1a8abSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1363d1a8abSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1463d1a8abSmrg GNU General Public License for more details.
1563d1a8abSmrg 
1663d1a8abSmrg Under Section 7 of GPL version 3, you are granted additional
1763d1a8abSmrg permissions described in the GCC Runtime Library Exception, version
1863d1a8abSmrg 3.1, as published by the Free Software Foundation.
1963d1a8abSmrg 
2063d1a8abSmrg You should have received a copy of the GNU General Public License and
2163d1a8abSmrg a copy of the GCC Runtime Library Exception along with this program;
2263d1a8abSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2363d1a8abSmrg <http://www.gnu.org/licenses/>.  */
2463d1a8abSmrg 
2563d1a8abSmrg #ifndef inhibit_libc
2663d1a8abSmrg /* Do code reading to identify a signal frame, and set the frame
2763d1a8abSmrg    state data appropriately.  See unwind-dw2.c for the structs.  */
2863d1a8abSmrg 
2963d1a8abSmrg #include <signal.h>
3063d1a8abSmrg #include <sys/ucontext.h>
3163d1a8abSmrg 
3263d1a8abSmrg #define MD_FALLBACK_FRAME_STATE_FOR alpha_fallback_frame_state
3363d1a8abSmrg 
3463d1a8abSmrg static _Unwind_Reason_Code
alpha_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)3563d1a8abSmrg alpha_fallback_frame_state (struct _Unwind_Context *context,
3663d1a8abSmrg 			    _Unwind_FrameState *fs)
3763d1a8abSmrg {
3863d1a8abSmrg   unsigned int *pc = context->ra;
3963d1a8abSmrg   struct sigcontext *sc;
4063d1a8abSmrg   long new_cfa;
4163d1a8abSmrg   int i;
4263d1a8abSmrg 
4363d1a8abSmrg   if (pc[0] != 0x47fe0410		/* mov $30,$16 */
4463d1a8abSmrg       || pc[2] != 0x00000083)		/* callsys */
4563d1a8abSmrg     return _URC_END_OF_STACK;
4663d1a8abSmrg   if (context->cfa == 0)
4763d1a8abSmrg     return _URC_END_OF_STACK;
4863d1a8abSmrg   if (pc[1] == 0x201f0067)		/* lda $0,NR_sigreturn */
4963d1a8abSmrg     sc = context->cfa;
5063d1a8abSmrg   else if (pc[1] == 0x201f015f)		/* lda $0,NR_rt_sigreturn */
5163d1a8abSmrg     {
5263d1a8abSmrg       struct rt_sigframe {
5363d1a8abSmrg 	siginfo_t info;
5463d1a8abSmrg 	ucontext_t uc;
5563d1a8abSmrg       } *rt_ = context->cfa;
560fc04c29Smrg       /* The void * cast is necessary to avoid an aliasing warning.
570fc04c29Smrg          The aliasing warning is correct, but should not be a problem
580fc04c29Smrg          because it does not alias anything.  */
590fc04c29Smrg       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
6063d1a8abSmrg     }
6163d1a8abSmrg   else
6263d1a8abSmrg     return _URC_END_OF_STACK;
6363d1a8abSmrg 
6463d1a8abSmrg   new_cfa = sc->sc_regs[30];
6563d1a8abSmrg   fs->regs.cfa_how = CFA_REG_OFFSET;
6663d1a8abSmrg   fs->regs.cfa_reg = 30;
6763d1a8abSmrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
6863d1a8abSmrg   for (i = 0; i < 30; ++i)
6963d1a8abSmrg     {
7063d1a8abSmrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
7163d1a8abSmrg       fs->regs.reg[i].loc.offset
7263d1a8abSmrg 	= (long) &sc->sc_regs[i] - new_cfa;
7363d1a8abSmrg     }
7463d1a8abSmrg   for (i = 0; i < 31; ++i)
7563d1a8abSmrg     {
7663d1a8abSmrg       fs->regs.reg[i+32].how = REG_SAVED_OFFSET;
7763d1a8abSmrg       fs->regs.reg[i+32].loc.offset
7863d1a8abSmrg 	= (long) &sc->sc_fpregs[i] - new_cfa;
7963d1a8abSmrg     }
8063d1a8abSmrg   fs->regs.reg[64].how = REG_SAVED_OFFSET;
8163d1a8abSmrg   fs->regs.reg[64].loc.offset = (long)&sc->sc_pc - new_cfa;
8263d1a8abSmrg   fs->retaddr_column = 64;
8363d1a8abSmrg   fs->signal_frame = 1;
8463d1a8abSmrg 
8563d1a8abSmrg   return _URC_NO_REASON;
8663d1a8abSmrg }
8763d1a8abSmrg 
8863d1a8abSmrg #define MD_FROB_UPDATE_CONTEXT alpha_frob_update_context
8963d1a8abSmrg 
9063d1a8abSmrg /* Fix up for signal handlers that don't have S flag set.  */
9163d1a8abSmrg 
9263d1a8abSmrg static void
alpha_frob_update_context(struct _Unwind_Context * context,_Unwind_FrameState * fs ATTRIBUTE_UNUSED)9363d1a8abSmrg alpha_frob_update_context (struct _Unwind_Context *context,
9463d1a8abSmrg 			   _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
9563d1a8abSmrg {
9663d1a8abSmrg   unsigned int *pc = context->ra;
9763d1a8abSmrg 
9863d1a8abSmrg   if (pc[0] == 0x47fe0410		/* mov $30,$16 */
9963d1a8abSmrg       && pc[2] == 0x00000083		/* callsys */
10063d1a8abSmrg       && (pc[1] == 0x201f0067		/* lda $0,NR_sigreturn */
10163d1a8abSmrg 	  || pc[1] == 0x201f015f))	/* lda $0,NR_rt_sigreturn */
10263d1a8abSmrg     _Unwind_SetSignalFrame (context, 1);
10363d1a8abSmrg }
10463d1a8abSmrg #endif
105