sol2-unwind.h revision 1.1
1/* DWARF2 EH unwinding support for SPARC Solaris. 2 Copyright (C) 2009-2013 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/* Do code reading to identify a signal frame, and set the frame 26 state data appropriately. See unwind-dw2.c for the structs. */ 27 28#include <ucontext.h> 29#include <sys/frame.h> 30#include <sys/stack.h> 31 32#ifdef __arch64__ 33 34#define IS_SIGHANDLER sparc64_is_sighandler 35 36static int 37sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes) 38{ 39 if (/* Solaris 9 - single-threaded 40 ---------------------------- 41 The pattern changes slightly in different versions of the 42 operating system, so we skip the comparison against pc[-6] for 43 Solaris 9. 44 45 <sigacthandler+24>: sra %i0, 0, %l1 46 47 Solaris 9 5/02: 48 <sigacthandler+28>: ldx [ %o2 + 0xf68 ], %g5 49 Solaris 9 9/05: 50 <sigacthandler+28>: ldx [ %o2 + 0xe50 ], %g5 51 52 <sigacthandler+32>: sllx %l1, 3, %g4 53 <sigacthandler+36>: mov %l1, %o0 54 <sigacthandler+40>: ldx [ %g4 + %g5 ], %l0 55 <sigacthandler+44>: call %l0 56 <sigacthandler+48>: mov %i2, %o2 57 <sigacthandler+52>: cmp %l1, 8 <--- PC */ 58 ( pc[-7] == 0xa33e2000 59 /* skip pc[-6] */ 60 && pc[-5] == 0x892c7003 61 && pc[-4] == 0x90100011 62 && pc[-3] == 0xe0590005 63 && pc[-2] == 0x9fc40000 64 && pc[-1] == 0x9410001a 65 && pc[ 0] == 0x80a46008)) 66 { 67 /* We need to move up one frame: 68 69 <signal handler> <-- context->cfa 70 sigacthandler 71 <kernel> 72 */ 73 *nframes = 1; 74 return 1; 75 } 76 77 if (/* Solaris 8+ - multi-threaded 78 ---------------------------- 79 <__sighndlr>: save %sp, -176, %sp 80 <__sighndlr+4>: mov %i0, %o0 81 <__sighndlr+8>: mov %i1, %o1 82 <__sighndlr+12>: call %i3 83 <__sighndlr+16>: mov %i2, %o2 84 <__sighndlr+20>: ret <--- PC 85 <__sighndlr+24>: restore */ 86 pc[-5] == 0x9de3bf50 87 && pc[-4] == 0x90100018 88 && pc[-3] == 0x92100019 89 && pc[-2] == 0x9fc6c000 90 && pc[-1] == 0x9410001a 91 && pc[ 0] == 0x81c7e008 92 && pc[ 1] == 0x81e80000) 93 { 94 /* We have observed different calling frames among different 95 versions of the operating system, so that we need to 96 discriminate using the upper frame. We look for the return 97 address of the caller frame (there is an offset of 15 double 98 words between the frame address and the place where this return 99 address is stored) in order to do some more pattern matching. */ 100 unsigned int cuh_pattern 101 = *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4); 102 103 if (cuh_pattern == 0x92100019) 104 /* This matches the call_user_handler pattern for Solaris 11. 105 This is the same setup as for Solaris 9, see below. */ 106 *nframes = 3; 107 108 else if (cuh_pattern == 0xd25fa7ef) 109 { 110 /* This matches the call_user_handler pattern for Solaris 10. 111 There are 2 cases so we look for the return address of the 112 caller's caller frame in order to do more pattern matching. */ 113 unsigned long sah_address = *(unsigned long *)(cfa + 176 + 15*8); 114 115 if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019) 116 /* This is the same setup as for Solaris 9, see below. */ 117 *nframes = 3; 118 else 119 /* The sigacthandler frame isn't present in the chain. 120 We need to move up two frames: 121 122 <signal handler> <-- context->cfa 123 __sighndlr 124 call_user_handler frame 125 <kernel> 126 */ 127 *nframes = 2; 128 } 129 130 else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013) 131 /* This matches the call_user_handler pattern for Solaris 9. 132 We need to move up three frames: 133 134 <signal handler> <-- context->cfa 135 __sighndlr 136 call_user_handler 137 sigacthandler 138 <kernel> 139 */ 140 *nframes = 3; 141 142 return 1; 143 } 144 145 return 0; 146} 147 148#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state 149 150#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context 151 152static void 153sparc64_frob_update_context (struct _Unwind_Context *context, 154 _Unwind_FrameState *fs) 155{ 156 /* The column of %sp contains the old CFA, not the old value of %sp. 157 The CFA offset already comprises the stack bias so, when %sp is the 158 CFA register, we must avoid counting the stack bias twice. Do not 159 do that for signal frames as the offset is artificial for them. */ 160 if (fs->regs.cfa_reg == __builtin_dwarf_sp_column () 161 && fs->regs.cfa_how == CFA_REG_OFFSET 162 && fs->regs.cfa_offset != 0 163 && !fs->signal_frame) 164 { 165 long i; 166 167 context->cfa -= STACK_BIAS; 168 169 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i) 170 if (fs->regs.reg[i].how == REG_SAVED_OFFSET) 171 _Unwind_SetGRPtr (context, i, 172 _Unwind_GetGRPtr (context, i) - STACK_BIAS); 173 } 174} 175 176#else 177 178#define IS_SIGHANDLER sparc_is_sighandler 179 180static int 181sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes) 182{ 183 if (/* Solaris 9 - single-threaded 184 ---------------------------- 185 The pattern changes slightly in different versions of the operating 186 system, so we skip the comparison against pc[-6]. 187 188 <sigacthandler+16>: add %o1, %o7, %o3 189 <sigacthandler+20>: mov %i1, %o1 190 191 <sigacthandler+24>: ld [ %o3 + <offset> ], %o2 192 193 <sigacthandler+28>: sll %i0, 2, %o0 194 <sigacthandler+32>: ld [ %o0 + %o2 ], %l0 195 <sigacthandler+36>: mov %i0, %o0 196 <sigacthandler+40>: call %l0 197 <sigacthandler+44>: mov %i2, %o2 198 <sigacthandler+48>: cmp %i0, 8 <--- PC */ 199 pc[-8] == 0x9602400f 200 && pc[-7] == 0x92100019 201 /* skip pc[-6] */ 202 && pc[-5] == 0x912e2002 203 && pc[-4] == 0xe002000a 204 && pc[-3] == 0x90100018 205 && pc[-2] == 0x9fc40000 206 && pc[-1] == 0x9410001a 207 && pc[ 0] == 0x80a62008) 208 { 209 /* We need to move up one frame: 210 211 <signal handler> <-- context->cfa 212 sigacthandler 213 <kernel> 214 */ 215 *nframes = 1; 216 return 1; 217 } 218 219 if(/* Solaris 8+ - multi-threaded 220 ---------------------------- 221 <__sighndlr>: save %sp, -96, %sp 222 <__sighndlr+4>: mov %i0, %o0 223 <__sighndlr+8>: mov %i1, %o1 224 <__sighndlr+12>: call %i3 225 <__sighndlr+16>: mov %i2, %o2 226 <__sighndlr+20>: ret <--- PC 227 <__sighndlr+24>: restore */ 228 pc[-5] == 0x9de3bfa0 229 && pc[-4] == 0x90100018 230 && pc[-3] == 0x92100019 231 && pc[-2] == 0x9fc6c000 232 && pc[-1] == 0x9410001a 233 && pc[ 0] == 0x81c7e008 234 && pc[ 1] == 0x81e80000) 235 { 236 /* We have observed different calling frames among different 237 versions of the operating system, so that we need to 238 discriminate using the upper frame. We look for the return 239 address of the caller frame (there is an offset of 15 words 240 between the frame address and the place where this return 241 address is stored) in order to do some more pattern matching. */ 242 unsigned int cuh_pattern 243 = *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4); 244 245 if (cuh_pattern == 0x92100019) 246 /* This matches the call_user_handler pattern for Solaris 11. 247 This is the same setup as for Solaris 9, see below. */ 248 *nframes = 3; 249 250 else if (cuh_pattern == 0xd407a04c) 251 { 252 /* This matches the call_user_handler pattern for Solaris 10. 253 There are 2 cases so we look for the return address of the 254 caller's caller frame in order to do more pattern matching. */ 255 unsigned int sah_address = *(unsigned int *)(cfa + 96 + 15*4); 256 257 if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019) 258 /* This is the same setup as for Solaris 9, see below. */ 259 *nframes = 3; 260 else 261 /* The sigacthandler frame isn't present in the chain. 262 We need to move up two frames: 263 264 <signal handler> <-- context->cfa 265 __sighndlr 266 call_user_handler frame 267 <kernel> 268 */ 269 *nframes = 2; 270 } 271 272 else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b) 273 /* This matches the call_user_handler pattern for Solaris 9. 274 We need to move up three frames: 275 276 <signal handler> <-- context->cfa 277 __sighndlr 278 call_user_handler 279 sigacthandler 280 <kernel> 281 */ 282 *nframes = 3; 283 284 return 1; 285 } 286 287 return 0; 288} 289 290#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state 291 292#endif 293 294static _Unwind_Reason_Code 295MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context, 296 _Unwind_FrameState *fs) 297{ 298 void *pc = context->ra; 299 struct frame *fp = (struct frame *) context->cfa; 300 int nframes; 301 void *this_cfa = context->cfa; 302 long new_cfa; 303 void *ra_location, *shifted_ra_location; 304 mcontext_t *mctx; 305 int i; 306 307 /* Deal with frame-less function from which a signal was raised. */ 308 if (_Unwind_IsSignalFrame (context)) 309 { 310 /* The CFA is by definition unmodified in this case. */ 311 fs->regs.cfa_how = CFA_REG_OFFSET; 312 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); 313 fs->regs.cfa_offset = 0; 314 315 /* This is the canonical RA column. */ 316 fs->retaddr_column = 15; 317 318 return _URC_NO_REASON; 319 } 320 321 if (IS_SIGHANDLER (pc, this_cfa, &nframes)) 322 { 323 struct handler_args { 324 struct frame frwin; 325 ucontext_t ucontext; 326 } *handler_args; 327 ucontext_t *ucp; 328 329 /* context->cfa points into the frame after the saved frame pointer and 330 saved pc (struct frame). 331 332 The ucontext_t structure is in the kernel frame after a struct 333 frame. Since the frame sizes vary even within OS releases, we 334 need to walk the stack to get there. */ 335 336 for (i = 0; i < nframes; i++) 337 fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS); 338 339 handler_args = (struct handler_args *) fp; 340 ucp = &handler_args->ucontext; 341 mctx = &ucp->uc_mcontext; 342 } 343 344 /* Exit if the pattern at the return address does not match the 345 previous three patterns. */ 346 else 347 return _URC_END_OF_STACK; 348 349 new_cfa = mctx->gregs[REG_SP]; 350 /* The frame address is %sp + STACK_BIAS in 64-bit mode. */ 351 new_cfa += STACK_BIAS; 352 353 fs->regs.cfa_how = CFA_REG_OFFSET; 354 fs->regs.cfa_reg = __builtin_dwarf_sp_column (); 355 fs->regs.cfa_offset = new_cfa - (long) this_cfa; 356 357 /* Restore global and out registers (in this order) from the 358 ucontext_t structure, uc_mcontext.gregs field. */ 359 for (i = 1; i < 16; i++) 360 { 361 /* We never restore %sp as everything is purely CFA-based. */ 362 if ((unsigned int) i == __builtin_dwarf_sp_column ()) 363 continue; 364 365 /* First the global registers and then the out registers. */ 366 fs->regs.reg[i].how = REG_SAVED_OFFSET; 367 fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa; 368 } 369 370 /* Just above the stack pointer there are 16 extended words in which 371 the register window (in and local registers) was saved. */ 372 for (i = 0; i < 16; i++) 373 { 374 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; 375 fs->regs.reg[i + 16].loc.offset = i*sizeof(long); 376 } 377 378 /* Check whether we need to restore FPU registers. */ 379 if (mctx->fpregs.fpu_qcnt) 380 { 381 for (i = 0; i < 32; i++) 382 { 383 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; 384 fs->regs.reg[i + 32].loc.offset 385 = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa; 386 } 387 388#ifdef __arch64__ 389 /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles. */ 390 for (i = 32; i < 64; i++) 391 { 392 if (i > 32 && (i & 1)) 393 continue; 394 395 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; 396 fs->regs.reg[i + 32].loc.offset 397 = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa; 398 } 399#endif 400 } 401 402 /* State the rules to find the kernel's code "return address", which is 403 the address of the active instruction when the signal was caught. 404 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we 405 need to preventively subtract it from the purported return address. */ 406 ra_location = &mctx->gregs[REG_PC]; 407 shifted_ra_location = &mctx->gregs[REG_Y]; 408 *(void **)shifted_ra_location = *(void **)ra_location - 8; 409 fs->retaddr_column = 0; 410 fs->regs.reg[0].how = REG_SAVED_OFFSET; 411 fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa; 412 fs->signal_frame = 1; 413 414 return _URC_NO_REASON; 415} 416