1/* DWARF2 EH unwinding support for AMD x86-64 and x86. 2 Copyright (C) 2004-2015 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 Don't use this at all if inhibit_libc is used. */ 28 29#ifndef inhibit_libc 30 31/* There's no sys/ucontext.h for glibc 2.0, so no 32 signal-turned-exceptions for them. There's also no configure-run for 33 the target, so we can't check on (e.g.) HAVE_SYS_UCONTEXT_H. Using the 34 target libc version macro should be enough. */ 35#if defined __GLIBC__ && !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) 36 37#include <signal.h> 38#include <sys/ucontext.h> 39 40#ifdef __x86_64__ 41 42#define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state 43 44static _Unwind_Reason_Code 45x86_64_fallback_frame_state (struct _Unwind_Context *context, 46 _Unwind_FrameState *fs) 47{ 48 unsigned char *pc = context->ra; 49 struct sigcontext *sc; 50 long new_cfa; 51 52 /* movq $__NR_rt_sigreturn, %rax ; syscall. */ 53#ifdef __LP64__ 54#define RT_SIGRETURN_SYSCALL 0x050f0000000fc0c7ULL 55#else 56#define RT_SIGRETURN_SYSCALL 0x050f40000201c0c7ULL 57#endif 58 if (*(unsigned char *)(pc+0) == 0x48 59 && *(unsigned long long *)(pc+1) == RT_SIGRETURN_SYSCALL) 60 { 61 struct ucontext *uc_ = context->cfa; 62 /* The void * cast is necessary to avoid an aliasing warning. 63 The aliasing warning is correct, but should not be a problem 64 because it does not alias anything. */ 65 sc = (struct sigcontext *) (void *) &uc_->uc_mcontext; 66 } 67 else 68 return _URC_END_OF_STACK; 69 70 new_cfa = sc->rsp; 71 fs->regs.cfa_how = CFA_REG_OFFSET; 72 /* Register 7 is rsp */ 73 fs->regs.cfa_reg = 7; 74 fs->regs.cfa_offset = new_cfa - (long) context->cfa; 75 76 /* The SVR4 register numbering macros aren't usable in libgcc. */ 77 fs->regs.reg[0].how = REG_SAVED_OFFSET; 78 fs->regs.reg[0].loc.offset = (long)&sc->rax - new_cfa; 79 fs->regs.reg[1].how = REG_SAVED_OFFSET; 80 fs->regs.reg[1].loc.offset = (long)&sc->rdx - new_cfa; 81 fs->regs.reg[2].how = REG_SAVED_OFFSET; 82 fs->regs.reg[2].loc.offset = (long)&sc->rcx - new_cfa; 83 fs->regs.reg[3].how = REG_SAVED_OFFSET; 84 fs->regs.reg[3].loc.offset = (long)&sc->rbx - new_cfa; 85 fs->regs.reg[4].how = REG_SAVED_OFFSET; 86 fs->regs.reg[4].loc.offset = (long)&sc->rsi - new_cfa; 87 fs->regs.reg[5].how = REG_SAVED_OFFSET; 88 fs->regs.reg[5].loc.offset = (long)&sc->rdi - new_cfa; 89 fs->regs.reg[6].how = REG_SAVED_OFFSET; 90 fs->regs.reg[6].loc.offset = (long)&sc->rbp - new_cfa; 91 fs->regs.reg[8].how = REG_SAVED_OFFSET; 92 fs->regs.reg[8].loc.offset = (long)&sc->r8 - new_cfa; 93 fs->regs.reg[9].how = REG_SAVED_OFFSET; 94 fs->regs.reg[9].loc.offset = (long)&sc->r9 - new_cfa; 95 fs->regs.reg[10].how = REG_SAVED_OFFSET; 96 fs->regs.reg[10].loc.offset = (long)&sc->r10 - new_cfa; 97 fs->regs.reg[11].how = REG_SAVED_OFFSET; 98 fs->regs.reg[11].loc.offset = (long)&sc->r11 - new_cfa; 99 fs->regs.reg[12].how = REG_SAVED_OFFSET; 100 fs->regs.reg[12].loc.offset = (long)&sc->r12 - new_cfa; 101 fs->regs.reg[13].how = REG_SAVED_OFFSET; 102 fs->regs.reg[13].loc.offset = (long)&sc->r13 - new_cfa; 103 fs->regs.reg[14].how = REG_SAVED_OFFSET; 104 fs->regs.reg[14].loc.offset = (long)&sc->r14 - new_cfa; 105 fs->regs.reg[15].how = REG_SAVED_OFFSET; 106 fs->regs.reg[15].loc.offset = (long)&sc->r15 - new_cfa; 107 fs->regs.reg[16].how = REG_SAVED_OFFSET; 108 fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa; 109 fs->retaddr_column = 16; 110 fs->signal_frame = 1; 111 return _URC_NO_REASON; 112} 113 114#else /* ifdef __x86_64__ */ 115 116#define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state 117 118static _Unwind_Reason_Code 119x86_fallback_frame_state (struct _Unwind_Context *context, 120 _Unwind_FrameState *fs) 121{ 122 unsigned char *pc = context->ra; 123 struct sigcontext *sc; 124 long new_cfa; 125 126 /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ 127 if (*(unsigned short *)(pc+0) == 0xb858 128 && *(unsigned int *)(pc+2) == 119 129 && *(unsigned short *)(pc+6) == 0x80cd) 130 sc = context->cfa + 4; 131 /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ 132 else if (*(unsigned char *)(pc+0) == 0xb8 133 && *(unsigned int *)(pc+1) == 173 134 && *(unsigned short *)(pc+5) == 0x80cd) 135 { 136 struct rt_sigframe { 137 int sig; 138 siginfo_t *pinfo; 139 void *puc; 140 siginfo_t info; 141 struct ucontext uc; 142 } *rt_ = context->cfa; 143 /* The void * cast is necessary to avoid an aliasing warning. 144 The aliasing warning is correct, but should not be a problem 145 because it does not alias anything. */ 146 sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext; 147 } 148 else 149 return _URC_END_OF_STACK; 150 151 new_cfa = sc->esp; 152 fs->regs.cfa_how = CFA_REG_OFFSET; 153 fs->regs.cfa_reg = 4; 154 fs->regs.cfa_offset = new_cfa - (long) context->cfa; 155 156 /* The SVR4 register numbering macros aren't usable in libgcc. */ 157 fs->regs.reg[0].how = REG_SAVED_OFFSET; 158 fs->regs.reg[0].loc.offset = (long)&sc->eax - new_cfa; 159 fs->regs.reg[3].how = REG_SAVED_OFFSET; 160 fs->regs.reg[3].loc.offset = (long)&sc->ebx - new_cfa; 161 fs->regs.reg[1].how = REG_SAVED_OFFSET; 162 fs->regs.reg[1].loc.offset = (long)&sc->ecx - new_cfa; 163 fs->regs.reg[2].how = REG_SAVED_OFFSET; 164 fs->regs.reg[2].loc.offset = (long)&sc->edx - new_cfa; 165 fs->regs.reg[6].how = REG_SAVED_OFFSET; 166 fs->regs.reg[6].loc.offset = (long)&sc->esi - new_cfa; 167 fs->regs.reg[7].how = REG_SAVED_OFFSET; 168 fs->regs.reg[7].loc.offset = (long)&sc->edi - new_cfa; 169 fs->regs.reg[5].how = REG_SAVED_OFFSET; 170 fs->regs.reg[5].loc.offset = (long)&sc->ebp - new_cfa; 171 fs->regs.reg[8].how = REG_SAVED_OFFSET; 172 fs->regs.reg[8].loc.offset = (long)&sc->eip - new_cfa; 173 fs->retaddr_column = 8; 174 fs->signal_frame = 1; 175 return _URC_NO_REASON; 176} 177 178#define MD_FROB_UPDATE_CONTEXT x86_frob_update_context 179 180/* Fix up for kernels that have vDSO, but don't have S flag in it. */ 181 182static void 183x86_frob_update_context (struct _Unwind_Context *context, 184 _Unwind_FrameState *fs ATTRIBUTE_UNUSED) 185{ 186 unsigned char *pc = context->ra; 187 188 /* movl $__NR_rt_sigreturn,%eax ; {int $0x80 | syscall} */ 189 if (*(unsigned char *)(pc+0) == 0xb8 190 && *(unsigned int *)(pc+1) == 173 191 && (*(unsigned short *)(pc+5) == 0x80cd 192 || *(unsigned short *)(pc+5) == 0x050f)) 193 _Unwind_SetSignalFrame (context, 1); 194} 195 196#endif /* ifdef __x86_64__ */ 197#endif /* not glibc 2.0 */ 198#endif /* ifdef inhibit_libc */ 199