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