1/* DWARF2 EH unwinding support for SH Linux. 2 Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 3, or (at your option) 9any later version. 10 11GCC is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16Under Section 7 of GPL version 3, you are granted additional 17permissions described in the GCC Runtime Library Exception, version 183.1, as published by the Free Software Foundation. 19 20You should have received a copy of the GNU General Public License and 21a copy of the GCC Runtime Library Exception along with this program; 22see 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 61static _Unwind_Reason_Code 62shmedia_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 struct siginfo *pinfo; 84 void *puc; 85 struct siginfo 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 148static _Unwind_Reason_Code 149sh_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 struct siginfo info; 183 struct ucontext 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