163d1a8abSmrg /* DWARF2 EH unwinding support for SH 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 
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    Don't use this at all if inhibit_libc is used.  */
2963d1a8abSmrg 
3063d1a8abSmrg #ifndef inhibit_libc
3163d1a8abSmrg 
3263d1a8abSmrg #include <signal.h>
3363d1a8abSmrg #include <sys/ucontext.h>
3463d1a8abSmrg #include "insn-constants.h"
3563d1a8abSmrg 
3663d1a8abSmrg #define SH_DWARF_FRAME_GP0	0
3763d1a8abSmrg #define SH_DWARF_FRAME_FP0	25
3863d1a8abSmrg #define SH_DWARF_FRAME_XD0	87
3963d1a8abSmrg #define SH_DWARF_FRAME_PR	17
4063d1a8abSmrg #define SH_DWARF_FRAME_GBR	18
4163d1a8abSmrg #define SH_DWARF_FRAME_MACH	20
4263d1a8abSmrg #define SH_DWARF_FRAME_MACL	21
4363d1a8abSmrg #define SH_DWARF_FRAME_PC	16
4463d1a8abSmrg #define SH_DWARF_FRAME_SR	22
4563d1a8abSmrg #define SH_DWARF_FRAME_FPUL	23
4663d1a8abSmrg #define SH_DWARF_FRAME_FPSCR	24
4763d1a8abSmrg 
4863d1a8abSmrg #define MD_FALLBACK_FRAME_STATE_FOR sh_fallback_frame_state
4963d1a8abSmrg 
5063d1a8abSmrg static _Unwind_Reason_Code
sh_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)5163d1a8abSmrg sh_fallback_frame_state (struct _Unwind_Context *context,
5263d1a8abSmrg 			 _Unwind_FrameState *fs)
5363d1a8abSmrg {
5463d1a8abSmrg   unsigned char *pc = context->ra;
5563d1a8abSmrg   struct sigcontext *sc;
5663d1a8abSmrg   long new_cfa;
5763d1a8abSmrg   int i;
5863d1a8abSmrg #if defined (__SH3E__) || defined (__SH4__)
5963d1a8abSmrg   int r;
6063d1a8abSmrg #endif
6163d1a8abSmrg 
6263d1a8abSmrg   /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77  (sigreturn)  */
6363d1a8abSmrg   /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad  (rt_sigreturn)  */
6463d1a8abSmrg   /* Newer kernel uses pad instructions to avoid an SH-4 core bug.  */
6563d1a8abSmrg   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
6663d1a8abSmrg      or r0,r0; 1: .short 0x77  (sigreturn)  */
6763d1a8abSmrg   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
6863d1a8abSmrg      or r0,r0; 1: .short 0xad  (rt_sigreturn)  */
6963d1a8abSmrg   if (((*(unsigned short *) (pc+0)  == 0x9300)
7063d1a8abSmrg        && (*(unsigned short *) (pc+2)  == 0xc310)
7163d1a8abSmrg        && (*(unsigned short *) (pc+4)  == 0x0077))
7263d1a8abSmrg       || (((*(unsigned short *) (pc+0)  == 0x9305)
7363d1a8abSmrg 	   && (*(unsigned short *) (pc+2)  == 0xc310)
7463d1a8abSmrg 	   && (*(unsigned short *) (pc+14)  == 0x0077))))
7563d1a8abSmrg     sc = context->cfa;
7663d1a8abSmrg   else if (((*(unsigned short *) (pc+0) == 0x9300)
7763d1a8abSmrg 	    && (*(unsigned short *) (pc+2)  == 0xc310)
7863d1a8abSmrg 	    && (*(unsigned short *) (pc+4)  == 0x00ad))
7963d1a8abSmrg 	   || (((*(unsigned short *) (pc+0) == 0x9305)
8063d1a8abSmrg 		&& (*(unsigned short *) (pc+2)  == 0xc310)
8163d1a8abSmrg 		&& (*(unsigned short *) (pc+14)  == 0x00ad))))
8263d1a8abSmrg     {
8363d1a8abSmrg       struct rt_sigframe {
8463d1a8abSmrg 	siginfo_t info;
8563d1a8abSmrg 	ucontext_t uc;
8663d1a8abSmrg       } *rt_ = context->cfa;
8763d1a8abSmrg       /* The void * cast is necessary to avoid an aliasing warning.
8863d1a8abSmrg          The aliasing warning is correct, but should not be a problem
8963d1a8abSmrg          because it does not alias anything.  */
9063d1a8abSmrg       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
9163d1a8abSmrg     }
9263d1a8abSmrg   else
9363d1a8abSmrg     return _URC_END_OF_STACK;
9463d1a8abSmrg 
9563d1a8abSmrg   new_cfa = sc->sc_regs[15];
9663d1a8abSmrg   fs->regs.cfa_how = CFA_REG_OFFSET;
9763d1a8abSmrg   fs->regs.cfa_reg = 15;
9863d1a8abSmrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
9963d1a8abSmrg 
10063d1a8abSmrg   for (i = 0; i < 15; i++)
10163d1a8abSmrg     {
10263d1a8abSmrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
10363d1a8abSmrg       fs->regs.reg[i].loc.offset
10463d1a8abSmrg 	= (long)&(sc->sc_regs[i]) - new_cfa;
10563d1a8abSmrg     }
10663d1a8abSmrg 
10763d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_PR].how = REG_SAVED_OFFSET;
10863d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_PR].loc.offset
10963d1a8abSmrg     = (long)&(sc->sc_pr) - new_cfa;
11063d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
11163d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
11263d1a8abSmrg     = (long)&(sc->sc_sr) - new_cfa;
11363d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_GBR].how = REG_SAVED_OFFSET;
11463d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_GBR].loc.offset
11563d1a8abSmrg     = (long)&(sc->sc_gbr) - new_cfa;
11663d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_MACH].how = REG_SAVED_OFFSET;
11763d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_MACH].loc.offset
11863d1a8abSmrg     = (long)&(sc->sc_mach) - new_cfa;
11963d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_MACL].how = REG_SAVED_OFFSET;
12063d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_MACL].loc.offset
12163d1a8abSmrg     = (long)&(sc->sc_macl) - new_cfa;
12263d1a8abSmrg 
12363d1a8abSmrg #if defined (__SH3E__) || defined (__SH4__)
12463d1a8abSmrg   r = SH_DWARF_FRAME_FP0;
12563d1a8abSmrg   for (i = 0; i < 16; i++)
12663d1a8abSmrg     {
12763d1a8abSmrg       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
12863d1a8abSmrg       fs->regs.reg[r+i].loc.offset
12963d1a8abSmrg 	= (long)&(sc->sc_fpregs[i]) - new_cfa;
13063d1a8abSmrg     }
13163d1a8abSmrg 
13263d1a8abSmrg   r = SH_DWARF_FRAME_XD0;
13363d1a8abSmrg   for (i = 0; i < 8; i++)
13463d1a8abSmrg     {
13563d1a8abSmrg       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
13663d1a8abSmrg       fs->regs.reg[r+i].loc.offset
13763d1a8abSmrg 	= (long)&(sc->sc_xfpregs[2*i]) - new_cfa;
13863d1a8abSmrg     }
13963d1a8abSmrg 
14063d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_FPUL].how = REG_SAVED_OFFSET;
14163d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset
14263d1a8abSmrg     = (long)&(sc->sc_fpul) - new_cfa;
14363d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
14463d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
14563d1a8abSmrg     = (long)&(sc->sc_fpscr) - new_cfa;
14663d1a8abSmrg #endif
14763d1a8abSmrg 
14863d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_PC].how = REG_SAVED_OFFSET;
14963d1a8abSmrg   fs->regs.reg[SH_DWARF_FRAME_PC].loc.offset
15063d1a8abSmrg     = (long)&(sc->sc_pc) - new_cfa;
15163d1a8abSmrg   fs->retaddr_column = SH_DWARF_FRAME_PC;
15263d1a8abSmrg   fs->signal_frame = 1;
15363d1a8abSmrg   return _URC_NO_REASON;
15463d1a8abSmrg }
15563d1a8abSmrg 
15663d1a8abSmrg #endif /* inhibit_libc */
157