Home | History | Annotate | Line # | Download | only in sh
linux-unwind.h revision 1.1.1.5
      1 /* DWARF2 EH unwinding support for SH Linux.
      2    Copyright (C) 2004-2016 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 # if defined (__SH5__)
     37 #define SH_DWARF_FRAME_GP0	0
     38 #define SH_DWARF_FRAME_FP0	77
     39 #define SH_DWARF_FRAME_BT0	68
     40 #define SH_DWARF_FRAME_PR_MEDIA	18
     41 #define SH_DWARF_FRAME_SR	65
     42 #define SH_DWARF_FRAME_FPSCR	76
     43 #else
     44 #define SH_DWARF_FRAME_GP0	0
     45 #define SH_DWARF_FRAME_FP0	25
     46 #define SH_DWARF_FRAME_XD0	87
     47 #define SH_DWARF_FRAME_PR	17
     48 #define SH_DWARF_FRAME_GBR	18
     49 #define SH_DWARF_FRAME_MACH	20
     50 #define SH_DWARF_FRAME_MACL	21
     51 #define SH_DWARF_FRAME_PC	16
     52 #define SH_DWARF_FRAME_SR	22
     53 #define SH_DWARF_FRAME_FPUL	23
     54 #define SH_DWARF_FRAME_FPSCR	24
     55 #endif /* defined (__SH5__) */
     56 
     57 #if defined (__SH5__)
     58 
     59 #define MD_FALLBACK_FRAME_STATE_FOR shmedia_fallback_frame_state
     60 
     61 static _Unwind_Reason_Code
     62 shmedia_fallback_frame_state (struct _Unwind_Context *context,
     63 			      _Unwind_FrameState *fs)
     64 {
     65   unsigned char *pc = context->ra;
     66   struct sigcontext *sc;
     67   long new_cfa;
     68   int i, r;
     69 
     70   /* movi 0x10,r9; shori 0x77,r9; trapa	r9; nop (sigreturn)  */
     71   /* movi 0x10,r9; shori 0xad,r9; trapa	r9; nop (rt_sigreturn)  */
     72   if ((*(unsigned long *) (pc-1)  == 0xcc004090)
     73       && (*(unsigned long *) (pc+3)  == 0xc801dc90)
     74       && (*(unsigned long *) (pc+7)  == 0x6c91fff0)
     75       && (*(unsigned long *) (pc+11)  == 0x6ff0fff0))
     76     sc = context->cfa;
     77   else if ((*(unsigned long *) (pc-1)  == 0xcc004090)
     78 	   && (*(unsigned long *) (pc+3)  == 0xc802b490)
     79 	   && (*(unsigned long *) (pc+7)  == 0x6c91fff0)
     80 	   && (*(unsigned long *) (pc+11)  == 0x6ff0fff0))
     81     {
     82       struct rt_sigframe {
     83 	siginfo_t *pinfo;
     84 	void *puc;
     85 	siginfo_t info;
     86 	struct ucontext uc;
     87       } *rt_ = context->cfa;
     88       /* The void * cast is necessary to avoid an aliasing warning.
     89          The aliasing warning is correct, but should not be a problem
     90          because it does not alias anything.  */
     91       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
     92     }
     93   else
     94     return _URC_END_OF_STACK;
     95 
     96   new_cfa = sc->sc_regs[15];
     97   fs->regs.cfa_how = CFA_REG_OFFSET;
     98   fs->regs.cfa_reg = 15;
     99   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
    100 
    101   for (i = 0; i < 63; i++)
    102     {
    103       if (i == 15)
    104 	continue;
    105 
    106       fs->regs.reg[i].how = REG_SAVED_OFFSET;
    107       fs->regs.reg[i].loc.offset
    108 	= (long)&(sc->sc_regs[i]) - new_cfa;
    109     }
    110 
    111   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
    112   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
    113     = (long)&(sc->sc_sr) - new_cfa;
    114 
    115   r = SH_DWARF_FRAME_BT0;
    116   for (i = 0; i < 8; i++)
    117     {
    118       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
    119       fs->regs.reg[r+i].loc.offset
    120 	= (long)&(sc->sc_tregs[i]) - new_cfa;
    121     }
    122 
    123   r = SH_DWARF_FRAME_FP0;
    124   for (i = 0; i < 32; i++)
    125     {
    126       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
    127       fs->regs.reg[r+i].loc.offset
    128 	= (long)&(sc->sc_fpregs[i]) - new_cfa;
    129     }
    130 
    131   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
    132   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
    133     = (long)&(sc->sc_fpscr) - new_cfa;
    134 
    135   /* We use the slot for the zero register to save return address.  */
    136   fs->regs.reg[63].how = REG_SAVED_OFFSET;
    137   fs->regs.reg[63].loc.offset
    138     = (long)&(sc->sc_pc) - new_cfa;
    139   fs->retaddr_column = 63;
    140   fs->signal_frame = 1;
    141   return _URC_NO_REASON;
    142 }
    143 
    144 #else /* defined (__SH5__) */
    145 
    146 #define MD_FALLBACK_FRAME_STATE_FOR sh_fallback_frame_state
    147 
    148 static _Unwind_Reason_Code
    149 sh_fallback_frame_state (struct _Unwind_Context *context,
    150 			 _Unwind_FrameState *fs)
    151 {
    152   unsigned char *pc = context->ra;
    153   struct sigcontext *sc;
    154   long new_cfa;
    155   int i;
    156 #if defined (__SH3E__) || defined (__SH4__)
    157   int r;
    158 #endif
    159 
    160   /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77  (sigreturn)  */
    161   /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad  (rt_sigreturn)  */
    162   /* Newer kernel uses pad instructions to avoid an SH-4 core bug.  */
    163   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
    164      or r0,r0; 1: .short 0x77  (sigreturn)  */
    165   /* mov.w 1f,r3; trapa #0x10; or r0,r0; or r0,r0; or r0,r0; or r0,r0;
    166      or r0,r0; 1: .short 0xad  (rt_sigreturn)  */
    167   if (((*(unsigned short *) (pc+0)  == 0x9300)
    168        && (*(unsigned short *) (pc+2)  == 0xc310)
    169        && (*(unsigned short *) (pc+4)  == 0x0077))
    170       || (((*(unsigned short *) (pc+0)  == 0x9305)
    171 	   && (*(unsigned short *) (pc+2)  == 0xc310)
    172 	   && (*(unsigned short *) (pc+14)  == 0x0077))))
    173     sc = context->cfa;
    174   else if (((*(unsigned short *) (pc+0) == 0x9300)
    175 	    && (*(unsigned short *) (pc+2)  == 0xc310)
    176 	    && (*(unsigned short *) (pc+4)  == 0x00ad))
    177 	   || (((*(unsigned short *) (pc+0) == 0x9305)
    178 		&& (*(unsigned short *) (pc+2)  == 0xc310)
    179 		&& (*(unsigned short *) (pc+14)  == 0x00ad))))
    180     {
    181       struct rt_sigframe {
    182 	siginfo_t info;
    183 	ucontext_t uc;
    184       } *rt_ = context->cfa;
    185       /* The void * cast is necessary to avoid an aliasing warning.
    186          The aliasing warning is correct, but should not be a problem
    187          because it does not alias anything.  */
    188       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
    189     }
    190   else
    191     return _URC_END_OF_STACK;
    192 
    193   new_cfa = sc->sc_regs[15];
    194   fs->regs.cfa_how = CFA_REG_OFFSET;
    195   fs->regs.cfa_reg = 15;
    196   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
    197 
    198   for (i = 0; i < 15; i++)
    199     {
    200       fs->regs.reg[i].how = REG_SAVED_OFFSET;
    201       fs->regs.reg[i].loc.offset
    202 	= (long)&(sc->sc_regs[i]) - new_cfa;
    203     }
    204 
    205   fs->regs.reg[SH_DWARF_FRAME_PR].how = REG_SAVED_OFFSET;
    206   fs->regs.reg[SH_DWARF_FRAME_PR].loc.offset
    207     = (long)&(sc->sc_pr) - new_cfa;
    208   fs->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET;
    209   fs->regs.reg[SH_DWARF_FRAME_SR].loc.offset
    210     = (long)&(sc->sc_sr) - new_cfa;
    211   fs->regs.reg[SH_DWARF_FRAME_GBR].how = REG_SAVED_OFFSET;
    212   fs->regs.reg[SH_DWARF_FRAME_GBR].loc.offset
    213     = (long)&(sc->sc_gbr) - new_cfa;
    214   fs->regs.reg[SH_DWARF_FRAME_MACH].how = REG_SAVED_OFFSET;
    215   fs->regs.reg[SH_DWARF_FRAME_MACH].loc.offset
    216     = (long)&(sc->sc_mach) - new_cfa;
    217   fs->regs.reg[SH_DWARF_FRAME_MACL].how = REG_SAVED_OFFSET;
    218   fs->regs.reg[SH_DWARF_FRAME_MACL].loc.offset
    219     = (long)&(sc->sc_macl) - new_cfa;
    220 
    221 #if defined (__SH3E__) || defined (__SH4__)
    222   r = SH_DWARF_FRAME_FP0;
    223   for (i = 0; i < 16; i++)
    224     {
    225       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
    226       fs->regs.reg[r+i].loc.offset
    227 	= (long)&(sc->sc_fpregs[i]) - new_cfa;
    228     }
    229 
    230   r = SH_DWARF_FRAME_XD0;
    231   for (i = 0; i < 8; i++)
    232     {
    233       fs->regs.reg[r+i].how = REG_SAVED_OFFSET;
    234       fs->regs.reg[r+i].loc.offset
    235 	= (long)&(sc->sc_xfpregs[2*i]) - new_cfa;
    236     }
    237 
    238   fs->regs.reg[SH_DWARF_FRAME_FPUL].how = REG_SAVED_OFFSET;
    239   fs->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset
    240     = (long)&(sc->sc_fpul) - new_cfa;
    241   fs->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET;
    242   fs->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset
    243     = (long)&(sc->sc_fpscr) - new_cfa;
    244 #endif
    245 
    246   fs->regs.reg[SH_DWARF_FRAME_PC].how = REG_SAVED_OFFSET;
    247   fs->regs.reg[SH_DWARF_FRAME_PC].loc.offset
    248     = (long)&(sc->sc_pc) - new_cfa;
    249   fs->retaddr_column = SH_DWARF_FRAME_PC;
    250   fs->signal_frame = 1;
    251   return _URC_NO_REASON;
    252 }
    253 #endif /* defined (__SH5__) */
    254 
    255 #endif /* inhibit_libc */
    256