1/* DWARF2 EH unwinding support for PA HP-UX. 2 Copyright (C) 2005 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 2, or (at your option) 9any later version. 10 11In addition to the permissions in the GNU General Public License, the 12Free Software Foundation gives you unlimited permission to link the 13compiled version of this file with other programs, and to distribute 14those programs without any restriction coming from the use of this 15file. (The General Public License restrictions do apply in other 16respects; for example, they cover modification of the file, and 17distribution when not linked into another program.) 18 19GCC is distributed in the hope that it will be useful, 20but WITHOUT ANY WARRANTY; without even the implied warranty of 21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22GNU General Public License for more details. 23 24You should have received a copy of the GNU General Public License 25along with GCC; see the file COPYING. If not, write to 26the Free Software Foundation, 51 Franklin Street, Fifth Floor, 27Boston, MA 02110-1301, USA. */ 28 29/* Do code reading to identify a signal frame, and set the frame 30 state data appropriately. See unwind-dw2.c for the structs. */ 31 32#include <signal.h> 33#include <sys/ucontext.h> 34#include <unistd.h> 35 36/* FIXME: We currently ignore the high halves of general, space and 37 control registers on PA 2.0 machines for applications using the 38 32-bit runtime. We don't restore space registers or the floating 39 point status registers. */ 40 41#define MD_FALLBACK_FRAME_STATE_FOR pa_fallback_frame_state 42 43/* HP-UX 10.X doesn't define GetSSReg. */ 44#ifndef GetSSReg 45#define GetSSReg(ssp, ss_reg) \ 46 ((UseWideRegs (ssp)) \ 47 ? (ssp)->ss_wide.ss_32.ss_reg ## _lo \ 48 : (ssp)->ss_narrow.ss_reg) 49#endif 50 51#if TARGET_64BIT 52#define GetSSRegAddr(ssp, ss_reg) ((long) &((ssp)->ss_wide.ss_64.ss_reg)) 53#else 54#define GetSSRegAddr(ssp, ss_reg) \ 55 ((UseWideRegs (ssp)) \ 56 ? (long) &((ssp)->ss_wide.ss_32.ss_reg ## _lo) \ 57 : (long) &((ssp)->ss_narrow.ss_reg)) 58#endif 59 60#define UPDATE_FS_FOR_SAR(FS, N) \ 61 (FS)->regs.reg[N].how = REG_SAVED_OFFSET; \ 62 (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_cr11) - new_cfa 63 64#define UPDATE_FS_FOR_GR(FS, GRN, N) \ 65 (FS)->regs.reg[N].how = REG_SAVED_OFFSET; \ 66 (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_gr##GRN) - new_cfa 67 68#define UPDATE_FS_FOR_FR(FS, FRN, N) \ 69 (FS)->regs.reg[N].how = REG_SAVED_OFFSET; \ 70 (FS)->regs.reg[N].loc.offset = (long) &(mc->ss_fr##FRN) - new_cfa; 71 72#define UPDATE_FS_FOR_PC(FS, N) \ 73 (FS)->regs.reg[N].how = REG_SAVED_OFFSET; \ 74 (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_pcoq_head) - new_cfa 75 76/* Extract bit field from word using HP's numbering (MSB = 0). */ 77#define GET_FIELD(X, FROM, TO) \ 78 ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) 79 80static inline int 81sign_extend (int x, int len) 82{ 83 int signbit = (1 << (len - 1)); 84 int mask = (signbit << 1) - 1; 85 return ((x & mask) ^ signbit) - signbit; 86} 87 88/* Extract a 17-bit signed constant from branch instructions. */ 89static inline int 90extract_17 (unsigned word) 91{ 92 return sign_extend (GET_FIELD (word, 19, 28) 93 | GET_FIELD (word, 29, 29) << 10 94 | GET_FIELD (word, 11, 15) << 11 95 | (word & 0x1) << 16, 17); 96} 97 98/* Extract a 22-bit signed constant from branch instructions. */ 99static inline int 100extract_22 (unsigned word) 101{ 102 return sign_extend (GET_FIELD (word, 19, 28) 103 | GET_FIELD (word, 29, 29) << 10 104 | GET_FIELD (word, 11, 15) << 11 105 | GET_FIELD (word, 6, 10) << 16 106 | (word & 0x1) << 21, 22); 107} 108 109static _Unwind_Reason_Code 110pa_fallback_frame_state (struct _Unwind_Context *context, 111 _Unwind_FrameState *fs) 112{ 113 static long cpu; 114 unsigned int *pc = (unsigned int *) context->ra; 115 116 if (pc == 0) 117 return _URC_END_OF_STACK; 118 119 /* Check if the return address points to an export stub (PA 1.1 or 2.0). */ 120 if ((!TARGET_64BIT 121 && *(pc + 0) == 0x4bc23fd1 /* ldw -18(sp),rp */ 122 && *(pc + 1) == 0x004010a1 /* ldsid (rp),r1 */ 123 && *(pc + 2) == 0x00011820 /* mtsp r1,sr0 */ 124 && *(pc + 3) == 0xe0400002) /* be,n 0(sr0,rp) */ 125 || 126 (!TARGET_64BIT 127 && *(pc + 0) == 0x4bc23fd1 /* ldw -18(sp),rp */ 128 && *(pc + 1) == 0xe840d002)) /* bve,n (rp) */ 129 { 130 fs->cfa_how = CFA_REG_OFFSET; 131 fs->cfa_reg = 30; 132 fs->cfa_offset = 0; 133 134 fs->retaddr_column = 0; 135 fs->regs.reg[0].how = REG_SAVED_OFFSET; 136 fs->regs.reg[0].loc.offset = -24; 137 138 return _URC_NO_REASON; 139 } 140 141 /* Check if the return address is an export stub as signal handlers 142 may return via an export stub. */ 143 if (!TARGET_64BIT 144 && (*pc & 0xffe0e002) == 0xe8400000 /* bl x,r2 */ 145 && *(pc + 1) == 0x08000240 /* nop */ 146 && *(pc + 2) == 0x4bc23fd1 /* ldw -18(sp),rp */ 147 && *(pc + 3) == 0x004010a1 /* ldsid (rp),r1 */ 148 && *(pc + 4) == 0x00011820 /* mtsp r1,sr0 */ 149 && *(pc + 5) == 0xe0400002) /* be,n 0(sr0,rp) */ 150 /* Extract target address from PA 1.x 17-bit branch. */ 151 pc += extract_17 (*pc) + 2; 152 else if (!TARGET_64BIT 153 && (*pc & 0xfc00e002) == 0xe800a000 /* b,l x,r2 */ 154 && *(pc + 1) == 0x08000240 /* nop */ 155 && *(pc + 2) == 0x4bc23fd1 /* ldw -18(sp),rp */ 156 && *(pc + 3) == 0xe840d002) /* bve,n (rp) */ 157 /* Extract target address from PA 2.0 22-bit branch. */ 158 pc += extract_22 (*pc) + 2; 159 160 /* Now check if the return address is one of the signal handler 161 returns, _sigreturn or _sigsetreturn. */ 162 if ((TARGET_64BIT 163 && *(pc + 0) == 0x53db3f51 /* ldd -58(sp),dp */ 164 && *(pc + 8) == 0x34160116 /* ldi 8b,r22 */ 165 && *(pc + 9) == 0x08360ac1 /* shladd,l r22,3,r1,r1 */ 166 && *(pc + 10) == 0x0c2010c1 /* ldd 0(r1),r1 */ 167 && *(pc + 11) == 0xe4202000) /* be,l 0(sr4,r1) */ 168 || 169 (TARGET_64BIT 170 && *(pc + 0) == 0x36dc0000 /* ldo 0(r22),ret0 */ 171 && *(pc + 6) == 0x341601c0 /* ldi e0,r22 */ 172 && *(pc + 7) == 0x08360ac1 /* shladd,l r22,3,r1,r1 */ 173 && *(pc + 8) == 0x0c2010c1 /* ldd 0(r1),r1 */ 174 && *(pc + 9) == 0xe4202000) /* be,l 0(sr4,r1) */ 175 || 176 (!TARGET_64BIT 177 && *(pc + 0) == 0x379a0000 /* ldo 0(ret0),r26 */ 178 && *(pc + 1) == 0x6bd33fc9 /* stw r19,-1c(sp) */ 179 && *(pc + 2) == 0x20200801 /* ldil L%-40000000,r1 */ 180 && *(pc + 3) == 0xe420e008 /* be,l 4(sr7,r1) */ 181 && *(pc + 4) == 0x34160116) /* ldi 8b,r22 */ 182 || 183 (!TARGET_64BIT 184 && *(pc + 0) == 0x6bd33fc9 /* stw r19,-1c(sp) */ 185 && *(pc + 1) == 0x20200801 /* ldil L%-40000000,r1 */ 186 && *(pc + 2) == 0xe420e008 /* be,l 4(sr7,r1) */ 187 && *(pc + 3) == 0x341601c0)) /* ldi e0,r22 */ 188 { 189 /* The previous stack pointer is saved at (long *)SP - 1. The 190 ucontext structure is offset from the start of the previous 191 frame by the siglocal_misc structure. */ 192 struct siglocalx *sl = (struct siglocalx *) 193 (*((long *) context->cfa - 1)); 194 mcontext_t *mc = &(sl->sl_uc.uc_mcontext); 195 196 long new_cfa = GetSSReg (mc, ss_sp); 197 198 fs->cfa_how = CFA_REG_OFFSET; 199 fs->cfa_reg = 30; 200 fs->cfa_offset = new_cfa - (long) context->cfa; 201 202 UPDATE_FS_FOR_GR (fs, 1, 1); 203 UPDATE_FS_FOR_GR (fs, 2, 2); 204 UPDATE_FS_FOR_GR (fs, 3, 3); 205 UPDATE_FS_FOR_GR (fs, 4, 4); 206 UPDATE_FS_FOR_GR (fs, 5, 5); 207 UPDATE_FS_FOR_GR (fs, 6, 6); 208 UPDATE_FS_FOR_GR (fs, 7, 7); 209 UPDATE_FS_FOR_GR (fs, 8, 8); 210 UPDATE_FS_FOR_GR (fs, 9, 9); 211 UPDATE_FS_FOR_GR (fs, 10, 10); 212 UPDATE_FS_FOR_GR (fs, 11, 11); 213 UPDATE_FS_FOR_GR (fs, 12, 12); 214 UPDATE_FS_FOR_GR (fs, 13, 13); 215 UPDATE_FS_FOR_GR (fs, 14, 14); 216 UPDATE_FS_FOR_GR (fs, 15, 15); 217 UPDATE_FS_FOR_GR (fs, 16, 16); 218 UPDATE_FS_FOR_GR (fs, 17, 17); 219 UPDATE_FS_FOR_GR (fs, 18, 18); 220 UPDATE_FS_FOR_GR (fs, 19, 19); 221 UPDATE_FS_FOR_GR (fs, 20, 20); 222 UPDATE_FS_FOR_GR (fs, 21, 21); 223 UPDATE_FS_FOR_GR (fs, 22, 22); 224 UPDATE_FS_FOR_GR (fs, 23, 23); 225 UPDATE_FS_FOR_GR (fs, 24, 24); 226 UPDATE_FS_FOR_GR (fs, 25, 25); 227 UPDATE_FS_FOR_GR (fs, 26, 26); 228 UPDATE_FS_FOR_GR (fs, 27, 27); 229 UPDATE_FS_FOR_GR (fs, 28, 28); 230 UPDATE_FS_FOR_GR (fs, 29, 29); 231 UPDATE_FS_FOR_GR (fs, 30, 30); 232 UPDATE_FS_FOR_GR (fs, 31, 31); 233 234 if (TARGET_64BIT) 235 { 236 UPDATE_FS_FOR_FR (fs, 4, 32); 237 UPDATE_FS_FOR_FR (fs, 5, 33); 238 UPDATE_FS_FOR_FR (fs, 6, 34); 239 UPDATE_FS_FOR_FR (fs, 7, 35); 240 UPDATE_FS_FOR_FR (fs, 8, 36); 241 UPDATE_FS_FOR_FR (fs, 9, 37); 242 UPDATE_FS_FOR_FR (fs, 10, 38); 243 UPDATE_FS_FOR_FR (fs, 11, 39); 244 UPDATE_FS_FOR_FR (fs, 12, 40); 245 UPDATE_FS_FOR_FR (fs, 13, 41); 246 UPDATE_FS_FOR_FR (fs, 14, 42); 247 UPDATE_FS_FOR_FR (fs, 15, 43); 248 UPDATE_FS_FOR_FR (fs, 16, 44); 249 UPDATE_FS_FOR_FR (fs, 17, 45); 250 UPDATE_FS_FOR_FR (fs, 18, 46); 251 UPDATE_FS_FOR_FR (fs, 19, 47); 252 UPDATE_FS_FOR_FR (fs, 20, 48); 253 UPDATE_FS_FOR_FR (fs, 21, 49); 254 UPDATE_FS_FOR_FR (fs, 22, 50); 255 UPDATE_FS_FOR_FR (fs, 23, 51); 256 UPDATE_FS_FOR_FR (fs, 24, 52); 257 UPDATE_FS_FOR_FR (fs, 25, 53); 258 UPDATE_FS_FOR_FR (fs, 26, 54); 259 UPDATE_FS_FOR_FR (fs, 27, 55); 260 UPDATE_FS_FOR_FR (fs, 28, 56); 261 UPDATE_FS_FOR_FR (fs, 29, 57); 262 UPDATE_FS_FOR_FR (fs, 30, 58); 263 UPDATE_FS_FOR_FR (fs, 31, 59); 264 265 UPDATE_FS_FOR_SAR (fs, 60); 266 } 267 else 268 { 269 UPDATE_FS_FOR_FR (fs, 4, 32); 270 UPDATE_FS_FOR_FR (fs, 5, 34); 271 UPDATE_FS_FOR_FR (fs, 6, 36); 272 UPDATE_FS_FOR_FR (fs, 7, 38); 273 UPDATE_FS_FOR_FR (fs, 8, 40); 274 UPDATE_FS_FOR_FR (fs, 9, 44); 275 UPDATE_FS_FOR_FR (fs, 10, 44); 276 UPDATE_FS_FOR_FR (fs, 11, 46); 277 UPDATE_FS_FOR_FR (fs, 12, 48); 278 UPDATE_FS_FOR_FR (fs, 13, 50); 279 UPDATE_FS_FOR_FR (fs, 14, 52); 280 UPDATE_FS_FOR_FR (fs, 15, 54); 281 282 if (!cpu) 283 cpu = sysconf (_SC_CPU_VERSION); 284 285 /* PA-RISC 1.0 only has 16 floating point registers. */ 286 if (cpu != CPU_PA_RISC1_0) 287 { 288 UPDATE_FS_FOR_FR (fs, 16, 56); 289 UPDATE_FS_FOR_FR (fs, 17, 58); 290 UPDATE_FS_FOR_FR (fs, 18, 60); 291 UPDATE_FS_FOR_FR (fs, 19, 62); 292 UPDATE_FS_FOR_FR (fs, 20, 64); 293 UPDATE_FS_FOR_FR (fs, 21, 66); 294 UPDATE_FS_FOR_FR (fs, 22, 68); 295 UPDATE_FS_FOR_FR (fs, 23, 70); 296 UPDATE_FS_FOR_FR (fs, 24, 72); 297 UPDATE_FS_FOR_FR (fs, 25, 74); 298 UPDATE_FS_FOR_FR (fs, 26, 76); 299 UPDATE_FS_FOR_FR (fs, 27, 78); 300 UPDATE_FS_FOR_FR (fs, 28, 80); 301 UPDATE_FS_FOR_FR (fs, 29, 82); 302 UPDATE_FS_FOR_FR (fs, 30, 84); 303 UPDATE_FS_FOR_FR (fs, 31, 86); 304 } 305 306 UPDATE_FS_FOR_SAR (fs, 88); 307 } 308 309 fs->retaddr_column = DWARF_ALT_FRAME_RETURN_COLUMN; 310 UPDATE_FS_FOR_PC (fs, DWARF_ALT_FRAME_RETURN_COLUMN); 311 312 return _URC_NO_REASON; 313 } 314 315 return _URC_END_OF_STACK; 316} 317