Home | History | Annotate | Line # | Download | only in sh
      1 /* DWARF2 EH unwinding support for SH Linux.
      2    Copyright (C) 2004-2024 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify
      7 it under the terms of the GNU General Public License as published by
      8 the Free Software Foundation; either version 3, or (at your option)
      9 any later version.
     10 
     11 GCC is distributed in the hope that it will be useful,
     12 but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 GNU General Public License for more details.
     15 
     16 Under Section 7 of GPL version 3, you are granted additional
     17 permissions described in the GCC Runtime Library Exception, version
     18 3.1, as published by the Free Software Foundation.
     19 
     20 You should have received a copy of the GNU General Public License and
     21 a copy of the GCC Runtime Library Exception along with this program;
     22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 <http://www.gnu.org/licenses/>.  */
     24 
     25 
     26 /* Do code reading to identify a signal frame, and set the frame
     27    state data appropriately.  See unwind-dw2.c for the structs.
     28    Don't use this at all if inhibit_libc is used.  */
     29 
     30 #ifndef inhibit_libc
     31 
     32 #include <signal.h>
     33 #include <sys/ucontext.h>
     34 #include "insn-constants.h"
     35 
     36 #define SH_DWARF_FRAME_GP0	0
     37 #define SH_DWARF_FRAME_FP0	25
     38 #define SH_DWARF_FRAME_XD0	87
     39 #define SH_DWARF_FRAME_PR	17
     40 #define SH_DWARF_FRAME_GBR	18
     41 #define SH_DWARF_FRAME_MACH	20
     42 #define SH_DWARF_FRAME_MACL	21
     43 #define SH_DWARF_FRAME_PC	16
     44 #define SH_DWARF_FRAME_SR	22
     45 #define SH_DWARF_FRAME_FPUL	23
     46 #define SH_DWARF_FRAME_FPSCR	24
     47 
     48 #define MD_FALLBACK_FRAME_STATE_FOR sh_fallback_frame_state
     49 
     50 static _Unwind_Reason_Code
     51 sh_fallback_frame_state (struct _Unwind_Context *context,
     52 			 _Unwind_FrameState *fs)
     53 {
     54   unsigned char *pc = context->ra;
     55   struct sigcontext *sc;
     56   long new_cfa;
     57   int i;
     58 #if defined (__SH3E__) || defined (__SH4__)
     59   int r;
     60 #endif
     61 
     62   /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77  (sigreturn)  */
     63   /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad  (rt_sigreturn)  */
     64   /* Newer kernel uses pad instructions to avoid an SH-4 core bug.  */
     65   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
     66      or r0,r0; 1: .short 0x77  (sigreturn)  */
     67   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
     68      or r0,r0; 1: .short 0xad  (rt_sigreturn)  */
     69   if (((*(unsigned short *) (pc+0)  == 0x9300)
     70        && (*(unsigned short *) (pc+2)  == 0xc310)
     71        && (*(unsigned short *) (pc+4)  == 0x0077))
     72       || (((*(unsigned short *) (pc+0)  == 0x9305)
     73 	   && (*(unsigned short *) (pc+2)  == 0xc310)
     74 	   && (*(unsigned short *) (pc+14)  == 0x0077))))
     75     sc = context->cfa;
     76   else if (((*(unsigned short *) (pc+0) == 0x9300)
     77 	    && (*(unsigned short *) (pc+2)  == 0xc310)
     78 	    && (*(unsigned short *) (pc+4)  == 0x00ad))
     79 	   || (((*(unsigned short *) (pc+0) == 0x9305)
     80 		&& (*(unsigned short *) (pc+2)  == 0xc310)
     81 		&& (*(unsigned short *) (pc+14)  == 0x00ad))))
     82     {
     83       struct rt_sigframe {
     84 	siginfo_t info;
     85 	ucontext_t uc;
     86       } *rt_ = context->cfa;
     87       /* The void * cast is necessary to avoid an aliasing warning.
     88          The aliasing warning is correct, but should not be a problem
     89          because it does not alias anything.  */
     90       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
     91     }
     92   else
     93     return _URC_END_OF_STACK;
     94 
     95   new_cfa = sc->sc_regs[15];
     96   fs->regs.cfa_how = CFA_REG_OFFSET;
     97   fs->regs.cfa_reg = 15;
     98   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
     99 
    100   for (i = 0; i < 15; i++)
    101     {
    102       fs->regs.how[i] = REG_SAVED_OFFSET;
    103       fs->regs.reg[i].loc.offset
    104 	= (long)&(sc->sc_regs[i]) - new_cfa;
    105     }
    106 
    107   fs->regs.how[SH_DWARF_FRAME_PR] = REG_SAVED_OFFSET;
    108   fs->regs.reg[SH_DWARF_FRAME_PR].loc.offset
    109     = (long)&(sc->sc_pr) - new_cfa;
    110   fs->regs.how[SH_DWARF_FRAME_SR] = REG_SAVED_OFFSET;
    111   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
    112     = (long)&(sc->sc_sr) - new_cfa;
    113   fs->regs.how[SH_DWARF_FRAME_GBR] = REG_SAVED_OFFSET;
    114   fs->regs.reg[SH_DWARF_FRAME_GBR].loc.offset
    115     = (long)&(sc->sc_gbr) - new_cfa;
    116   fs->regs.how[SH_DWARF_FRAME_MACH] = REG_SAVED_OFFSET;
    117   fs->regs.reg[SH_DWARF_FRAME_MACH].loc.offset
    118     = (long)&(sc->sc_mach) - new_cfa;
    119   fs->regs.how[SH_DWARF_FRAME_MACL] = REG_SAVED_OFFSET;
    120   fs->regs.reg[SH_DWARF_FRAME_MACL].loc.offset
    121     = (long)&(sc->sc_macl) - new_cfa;
    122 
    123 #if defined (__SH3E__) || defined (__SH4__)
    124   r = SH_DWARF_FRAME_FP0;
    125   for (i = 0; i < 16; i++)
    126     {
    127       fs->regs.how[r+i] = REG_SAVED_OFFSET;
    128       fs->regs.reg[r+i].loc.offset
    129 	= (long)&(sc->sc_fpregs[i]) - new_cfa;
    130     }
    131 
    132   r = SH_DWARF_FRAME_XD0;
    133   for (i = 0; i < 8; i++)
    134     {
    135       fs->regs.how[r+i] = REG_SAVED_OFFSET;
    136       fs->regs.reg[r+i].loc.offset
    137 	= (long)&(sc->sc_xfpregs[2*i]) - new_cfa;
    138     }
    139 
    140   fs->regs.how[SH_DWARF_FRAME_FPUL] = REG_SAVED_OFFSET;
    141   fs->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset
    142     = (long)&(sc->sc_fpul) - new_cfa;
    143   fs->regs.how[SH_DWARF_FRAME_FPSCR] = REG_SAVED_OFFSET;
    144   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
    145     = (long)&(sc->sc_fpscr) - new_cfa;
    146 #endif
    147 
    148   fs->regs.how[SH_DWARF_FRAME_PC] = REG_SAVED_OFFSET;
    149   fs->regs.reg[SH_DWARF_FRAME_PC].loc.offset
    150     = (long)&(sc->sc_pc) - new_cfa;
    151   fs->retaddr_column = SH_DWARF_FRAME_PC;
    152   fs->signal_frame = 1;
    153   return _URC_NO_REASON;
    154 }
    155 
    156 #endif /* inhibit_libc */
    157