1169689Skan/* DWARF2 EH unwinding support for AMD x86-64 and x86. 2169689Skan Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 3169689Skan 4169689SkanThis file is part of GCC. 5169689Skan 6169689SkanGCC is free software; you can redistribute it and/or modify 7169689Skanit under the terms of the GNU General Public License as published by 8169689Skanthe Free Software Foundation; either version 2, or (at your option) 9169689Skanany later version. 10169689Skan 11169689SkanIn addition to the permissions in the GNU General Public License, the 12169689SkanFree Software Foundation gives you unlimited permission to link the 13169689Skancompiled version of this file with other programs, and to distribute 14169689Skanthose programs without any restriction coming from the use of this 15169689Skanfile. (The General Public License restrictions do apply in other 16169689Skanrespects; for example, they cover modification of the file, and 17169689Skandistribution when not linked into another program.) 18169689Skan 19169689SkanGCC is distributed in the hope that it will be useful, 20169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 21169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22169689SkanGNU General Public License for more details. 23169689Skan 24169689SkanYou should have received a copy of the GNU General Public License 25169689Skanalong with GCC; see the file COPYING. If not, write to 26169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 27169689SkanBoston, MA 02110-1301, USA. */ 28169689Skan 29169689Skan/* Do code reading to identify a signal frame, and set the frame 30169689Skan state data appropriately. See unwind-dw2.c for the structs. 31169689Skan Don't use this at all if inhibit_libc is used. */ 32169689Skan 33169689Skan#ifndef inhibit_libc 34169689Skan 35169689Skan#ifdef __x86_64__ 36169689Skan 37169689Skan#include <signal.h> 38169689Skan#include <sys/ucontext.h> 39169689Skan 40169689Skan#define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state 41169689Skan 42169689Skanstatic _Unwind_Reason_Code 43169689Skanx86_64_fallback_frame_state (struct _Unwind_Context *context, 44169689Skan _Unwind_FrameState *fs) 45169689Skan{ 46169689Skan unsigned char *pc = context->ra; 47169689Skan struct sigcontext *sc; 48169689Skan long new_cfa; 49169689Skan 50169689Skan /* movq __NR_rt_sigreturn, %rax ; syscall */ 51169689Skan if (*(unsigned char *)(pc+0) == 0x48 52169689Skan && *(unsigned long *)(pc+1) == 0x050f0000000fc0c7) 53169689Skan { 54169689Skan struct ucontext *uc_ = context->cfa; 55169689Skan /* The void * cast is necessary to avoid an aliasing warning. 56169689Skan The aliasing warning is correct, but should not be a problem 57169689Skan because it does not alias anything. */ 58169689Skan sc = (struct sigcontext *) (void *) &uc_->uc_mcontext; 59169689Skan } 60169689Skan else 61169689Skan return _URC_END_OF_STACK; 62169689Skan 63169689Skan new_cfa = sc->rsp; 64169689Skan fs->cfa_how = CFA_REG_OFFSET; 65169689Skan /* Register 7 is rsp */ 66169689Skan fs->cfa_reg = 7; 67169689Skan fs->cfa_offset = new_cfa - (long) context->cfa; 68169689Skan 69169689Skan /* The SVR4 register numbering macros aren't usable in libgcc. */ 70169689Skan fs->regs.reg[0].how = REG_SAVED_OFFSET; 71169689Skan fs->regs.reg[0].loc.offset = (long)&sc->rax - new_cfa; 72169689Skan fs->regs.reg[1].how = REG_SAVED_OFFSET; 73169689Skan fs->regs.reg[1].loc.offset = (long)&sc->rdx - new_cfa; 74169689Skan fs->regs.reg[2].how = REG_SAVED_OFFSET; 75169689Skan fs->regs.reg[2].loc.offset = (long)&sc->rcx - new_cfa; 76169689Skan fs->regs.reg[3].how = REG_SAVED_OFFSET; 77169689Skan fs->regs.reg[3].loc.offset = (long)&sc->rbx - new_cfa; 78169689Skan fs->regs.reg[4].how = REG_SAVED_OFFSET; 79169689Skan fs->regs.reg[4].loc.offset = (long)&sc->rsi - new_cfa; 80169689Skan fs->regs.reg[5].how = REG_SAVED_OFFSET; 81169689Skan fs->regs.reg[5].loc.offset = (long)&sc->rdi - new_cfa; 82169689Skan fs->regs.reg[6].how = REG_SAVED_OFFSET; 83169689Skan fs->regs.reg[6].loc.offset = (long)&sc->rbp - new_cfa; 84169689Skan fs->regs.reg[8].how = REG_SAVED_OFFSET; 85169689Skan fs->regs.reg[8].loc.offset = (long)&sc->r8 - new_cfa; 86169689Skan fs->regs.reg[9].how = REG_SAVED_OFFSET; 87169689Skan fs->regs.reg[9].loc.offset = (long)&sc->r9 - new_cfa; 88169689Skan fs->regs.reg[10].how = REG_SAVED_OFFSET; 89169689Skan fs->regs.reg[10].loc.offset = (long)&sc->r10 - new_cfa; 90169689Skan fs->regs.reg[11].how = REG_SAVED_OFFSET; 91169689Skan fs->regs.reg[11].loc.offset = (long)&sc->r11 - new_cfa; 92169689Skan fs->regs.reg[12].how = REG_SAVED_OFFSET; 93169689Skan fs->regs.reg[12].loc.offset = (long)&sc->r12 - new_cfa; 94169689Skan fs->regs.reg[13].how = REG_SAVED_OFFSET; 95169689Skan fs->regs.reg[13].loc.offset = (long)&sc->r13 - new_cfa; 96169689Skan fs->regs.reg[14].how = REG_SAVED_OFFSET; 97169689Skan fs->regs.reg[14].loc.offset = (long)&sc->r14 - new_cfa; 98169689Skan fs->regs.reg[15].how = REG_SAVED_OFFSET; 99169689Skan fs->regs.reg[15].loc.offset = (long)&sc->r15 - new_cfa; 100169689Skan fs->regs.reg[16].how = REG_SAVED_OFFSET; 101169689Skan fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa; 102169689Skan fs->retaddr_column = 16; 103169689Skan fs->signal_frame = 1; 104169689Skan return _URC_NO_REASON; 105169689Skan} 106169689Skan 107169689Skan#else /* ifdef __x86_64__ */ 108169689Skan 109169689Skan/* There's no sys/ucontext.h for glibc 2.0, so no 110169689Skan signal-turned-exceptions for them. There's also no configure-run for 111169689Skan the target, so we can't check on (e.g.) HAVE_SYS_UCONTEXT_H. Using the 112169689Skan target libc version macro should be enough. */ 113169689Skan#if !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) 114169689Skan 115169689Skan#include <signal.h> 116169689Skan#include <sys/ucontext.h> 117169689Skan 118169689Skan#define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state 119169689Skan 120169689Skanstatic _Unwind_Reason_Code 121169689Skanx86_fallback_frame_state (struct _Unwind_Context *context, 122169689Skan _Unwind_FrameState *fs) 123169689Skan{ 124169689Skan unsigned char *pc = context->ra; 125169689Skan struct sigcontext *sc; 126169689Skan long new_cfa; 127169689Skan 128169689Skan /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ 129169689Skan if (*(unsigned short *)(pc+0) == 0xb858 130169689Skan && *(unsigned int *)(pc+2) == 119 131169689Skan && *(unsigned short *)(pc+6) == 0x80cd) 132169689Skan sc = context->cfa + 4; 133169689Skan /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ 134169689Skan else if (*(unsigned char *)(pc+0) == 0xb8 135169689Skan && *(unsigned int *)(pc+1) == 173 136169689Skan && *(unsigned short *)(pc+5) == 0x80cd) 137169689Skan { 138169689Skan struct rt_sigframe { 139169689Skan int sig; 140169689Skan struct siginfo *pinfo; 141169689Skan void *puc; 142169689Skan struct siginfo info; 143169689Skan struct ucontext uc; 144169689Skan } *rt_ = context->cfa; 145169689Skan /* The void * cast is necessary to avoid an aliasing warning. 146169689Skan The aliasing warning is correct, but should not be a problem 147169689Skan because it does not alias anything. */ 148169689Skan sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext; 149169689Skan } 150169689Skan else 151169689Skan return _URC_END_OF_STACK; 152169689Skan 153169689Skan new_cfa = sc->REG_NAME(esp); 154169689Skan fs->cfa_how = CFA_REG_OFFSET; 155169689Skan fs->cfa_reg = 4; 156169689Skan fs->cfa_offset = new_cfa - (long) context->cfa; 157169689Skan 158169689Skan /* The SVR4 register numbering macros aren't usable in libgcc. */ 159169689Skan fs->regs.reg[0].how = REG_SAVED_OFFSET; 160169689Skan fs->regs.reg[0].loc.offset = (long)&sc->REG_NAME(eax) - new_cfa; 161169689Skan fs->regs.reg[3].how = REG_SAVED_OFFSET; 162169689Skan fs->regs.reg[3].loc.offset = (long)&sc->REG_NAME(ebx) - new_cfa; 163169689Skan fs->regs.reg[1].how = REG_SAVED_OFFSET; 164169689Skan fs->regs.reg[1].loc.offset = (long)&sc->REG_NAME(ecx) - new_cfa; 165169689Skan fs->regs.reg[2].how = REG_SAVED_OFFSET; 166169689Skan fs->regs.reg[2].loc.offset = (long)&sc->REG_NAME(edx) - new_cfa; 167169689Skan fs->regs.reg[6].how = REG_SAVED_OFFSET; 168169689Skan fs->regs.reg[6].loc.offset = (long)&sc->REG_NAME(esi) - new_cfa; 169169689Skan fs->regs.reg[7].how = REG_SAVED_OFFSET; 170169689Skan fs->regs.reg[7].loc.offset = (long)&sc->REG_NAME(edi) - new_cfa; 171169689Skan fs->regs.reg[5].how = REG_SAVED_OFFSET; 172169689Skan fs->regs.reg[5].loc.offset = (long)&sc->REG_NAME(ebp) - new_cfa; 173169689Skan fs->regs.reg[8].how = REG_SAVED_OFFSET; 174169689Skan fs->regs.reg[8].loc.offset = (long)&sc->REG_NAME(eip) - new_cfa; 175169689Skan fs->retaddr_column = 8; 176169689Skan fs->signal_frame = 1; 177169689Skan return _URC_NO_REASON; 178169689Skan} 179169689Skan#endif /* not glibc 2.0 */ 180169689Skan#endif /* ifdef __x86_64__ */ 181169689Skan#endif /* ifdef inhibit_libc */ 182