1227825Stheraven/* DWARF2 EH unwinding support for AMD x86-64 and x86. 2227825Stheraven Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 3227825Stheraven 4227825StheravenThis file is part of GCC. 5227825Stheraven 6227825StheravenGCC is free software; you can redistribute it and/or modify 7227825Stheravenit under the terms of the GNU General Public License as published by 8227825Stheraventhe Free Software Foundation; either version 2, or (at your option) 9227825Stheravenany later version. 10227825Stheraven 11227825StheravenIn addition to the permissions in the GNU General Public License, the 12227825StheravenFree Software Foundation gives you unlimited permission to link the 13227825Stheravencompiled version of this file with other programs, and to distribute 14227825Stheraventhose programs without any restriction coming from the use of this 15227825Stheravenfile. (The General Public License restrictions do apply in other 16227825Stheravenrespects; for example, they cover modification of the file, and 17227825Stheravendistribution when not linked into another program.) 18227825Stheraven 19227825StheravenGCC is distributed in the hope that it will be useful, 20227825Stheravenbut WITHOUT ANY WARRANTY; without even the implied warranty of 21227825StheravenMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22227825StheravenGNU General Public License for more details. 23227825Stheraven 24227825StheravenYou should have received a copy of the GNU General Public License 25227825Stheravenalong with GCC; see the file COPYING. If not, write to 26227825Stheraventhe Free Software Foundation, 51 Franklin Street, Fifth Floor, 27227825StheravenBoston, MA 02110-1301, USA. */ 28227825Stheraven 29227825Stheraven/* Do code reading to identify a signal frame, and set the frame 30227825Stheraven state data appropriately. See unwind-dw2.c for the structs. 31227825Stheraven Don't use this at all if inhibit_libc is used. */ 32227825Stheraven 33227825Stheraven#ifndef inhibit_libc 34227825Stheraven 35227825Stheraven#ifdef __x86_64__ 36227825Stheraven 37227825Stheraven#include <signal.h> 38227825Stheraven#include <sys/ucontext.h> 39227825Stheraven 40227825Stheraven#define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state 41227825Stheraven 42227825Stheravenstatic _Unwind_Reason_Code 43227825Stheravenx86_64_fallback_frame_state (struct _Unwind_Context *context, 44227825Stheraven _Unwind_FrameState *fs) 45227825Stheraven{ 46227825Stheraven unsigned char *pc = context->ra; 47227825Stheraven struct sigcontext *sc; 48227825Stheraven long new_cfa; 49227825Stheraven 50227825Stheraven /* movq __NR_rt_sigreturn, %rax ; syscall */ 51227825Stheraven if (*(unsigned char *)(pc+0) == 0x48 52227825Stheraven && *(unsigned long *)(pc+1) == 0x050f0000000fc0c7) 53227825Stheraven { 54227825Stheraven struct ucontext *uc_ = context->cfa; 55227825Stheraven /* The void * cast is necessary to avoid an aliasing warning. 56227825Stheraven The aliasing warning is correct, but should not be a problem 57227825Stheraven because it does not alias anything. */ 58227825Stheraven sc = (struct sigcontext *) (void *) &uc_->uc_mcontext; 59227825Stheraven } 60227825Stheraven else 61227825Stheraven return _URC_END_OF_STACK; 62227825Stheraven 63227825Stheraven new_cfa = sc->rsp; 64227825Stheraven fs->cfa_how = CFA_REG_OFFSET; 65227825Stheraven /* Register 7 is rsp */ 66227825Stheraven fs->cfa_reg = 7; 67227825Stheraven fs->cfa_offset = new_cfa - (long) context->cfa; 68227825Stheraven 69227825Stheraven /* The SVR4 register numbering macros aren't usable in libgcc. */ 70227825Stheraven fs->regs.reg[0].how = REG_SAVED_OFFSET; 71227825Stheraven fs->regs.reg[0].loc.offset = (long)&sc->rax - new_cfa; 72227825Stheraven fs->regs.reg[1].how = REG_SAVED_OFFSET; 73227825Stheraven fs->regs.reg[1].loc.offset = (long)&sc->rdx - new_cfa; 74227825Stheraven fs->regs.reg[2].how = REG_SAVED_OFFSET; 75227825Stheraven fs->regs.reg[2].loc.offset = (long)&sc->rcx - new_cfa; 76227825Stheraven fs->regs.reg[3].how = REG_SAVED_OFFSET; 77227825Stheraven fs->regs.reg[3].loc.offset = (long)&sc->rbx - new_cfa; 78227825Stheraven fs->regs.reg[4].how = REG_SAVED_OFFSET; 79227825Stheraven fs->regs.reg[4].loc.offset = (long)&sc->rsi - new_cfa; 80227825Stheraven fs->regs.reg[5].how = REG_SAVED_OFFSET; 81227825Stheraven fs->regs.reg[5].loc.offset = (long)&sc->rdi - new_cfa; 82227825Stheraven fs->regs.reg[6].how = REG_SAVED_OFFSET; 83227825Stheraven fs->regs.reg[6].loc.offset = (long)&sc->rbp - new_cfa; 84227825Stheraven fs->regs.reg[8].how = REG_SAVED_OFFSET; 85227825Stheraven fs->regs.reg[8].loc.offset = (long)&sc->r8 - new_cfa; 86227825Stheraven fs->regs.reg[9].how = REG_SAVED_OFFSET; 87227825Stheraven fs->regs.reg[9].loc.offset = (long)&sc->r9 - new_cfa; 88227825Stheraven fs->regs.reg[10].how = REG_SAVED_OFFSET; 89227825Stheraven fs->regs.reg[10].loc.offset = (long)&sc->r10 - new_cfa; 90227825Stheraven fs->regs.reg[11].how = REG_SAVED_OFFSET; 91227825Stheraven fs->regs.reg[11].loc.offset = (long)&sc->r11 - new_cfa; 92227825Stheraven fs->regs.reg[12].how = REG_SAVED_OFFSET; 93227825Stheraven fs->regs.reg[12].loc.offset = (long)&sc->r12 - new_cfa; 94227825Stheraven fs->regs.reg[13].how = REG_SAVED_OFFSET; 95227825Stheraven fs->regs.reg[13].loc.offset = (long)&sc->r13 - new_cfa; 96227825Stheraven fs->regs.reg[14].how = REG_SAVED_OFFSET; 97227825Stheraven fs->regs.reg[14].loc.offset = (long)&sc->r14 - new_cfa; 98227825Stheraven fs->regs.reg[15].how = REG_SAVED_OFFSET; 99227825Stheraven fs->regs.reg[15].loc.offset = (long)&sc->r15 - new_cfa; 100227825Stheraven fs->regs.reg[16].how = REG_SAVED_OFFSET; 101227825Stheraven fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa; 102227825Stheraven fs->retaddr_column = 16; 103227825Stheraven fs->signal_frame = 1; 104227825Stheraven return _URC_NO_REASON; 105227825Stheraven} 106227825Stheraven 107227825Stheraven#else /* ifdef __x86_64__ */ 108227825Stheraven 109227825Stheraven/* There's no sys/ucontext.h for glibc 2.0, so no 110227825Stheraven signal-turned-exceptions for them. There's also no configure-run for 111227825Stheraven the target, so we can't check on (e.g.) HAVE_SYS_UCONTEXT_H. Using the 112227825Stheraven target libc version macro should be enough. */ 113227825Stheraven#if !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 0) 114227825Stheraven 115227825Stheraven#include <signal.h> 116227825Stheraven#include <sys/ucontext.h> 117227825Stheraven 118227825Stheraven#define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state 119227825Stheraven 120227825Stheravenstatic _Unwind_Reason_Code 121227825Stheravenx86_fallback_frame_state (struct _Unwind_Context *context, 122227825Stheraven _Unwind_FrameState *fs) 123227825Stheraven{ 124227825Stheraven unsigned char *pc = context->ra; 125227825Stheraven struct sigcontext *sc; 126227825Stheraven long new_cfa; 127227825Stheraven 128227825Stheraven /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ 129227825Stheraven if (*(unsigned short *)(pc+0) == 0xb858 130227825Stheraven && *(unsigned int *)(pc+2) == 119 131227825Stheraven && *(unsigned short *)(pc+6) == 0x80cd) 132227825Stheraven sc = context->cfa + 4; 133227825Stheraven /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ 134227825Stheraven else if (*(unsigned char *)(pc+0) == 0xb8 135227825Stheraven && *(unsigned int *)(pc+1) == 173 136227825Stheraven && *(unsigned short *)(pc+5) == 0x80cd) 137227825Stheraven { 138227825Stheraven struct rt_sigframe { 139227825Stheraven int sig; 140227825Stheraven struct siginfo *pinfo; 141227825Stheraven void *puc; 142227825Stheraven struct siginfo info; 143227825Stheraven struct ucontext uc; 144227825Stheraven } *rt_ = context->cfa; 145227825Stheraven /* The void * cast is necessary to avoid an aliasing warning. 146227825Stheraven The aliasing warning is correct, but should not be a problem 147227825Stheraven because it does not alias anything. */ 148227825Stheraven sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext; 149227825Stheraven } 150227825Stheraven else 151227825Stheraven return _URC_END_OF_STACK; 152227825Stheraven 153227825Stheraven new_cfa = sc->REG_NAME(esp); 154227825Stheraven fs->cfa_how = CFA_REG_OFFSET; 155227825Stheraven fs->cfa_reg = 4; 156227825Stheraven fs->cfa_offset = new_cfa - (long) context->cfa; 157227825Stheraven 158227825Stheraven /* The SVR4 register numbering macros aren't usable in libgcc. */ 159227825Stheraven fs->regs.reg[0].how = REG_SAVED_OFFSET; 160227825Stheraven fs->regs.reg[0].loc.offset = (long)&sc->REG_NAME(eax) - new_cfa; 161227825Stheraven fs->regs.reg[3].how = REG_SAVED_OFFSET; 162227825Stheraven fs->regs.reg[3].loc.offset = (long)&sc->REG_NAME(ebx) - new_cfa; 163227825Stheraven fs->regs.reg[1].how = REG_SAVED_OFFSET; 164227825Stheraven fs->regs.reg[1].loc.offset = (long)&sc->REG_NAME(ecx) - new_cfa; 165227825Stheraven fs->regs.reg[2].how = REG_SAVED_OFFSET; 166227825Stheraven fs->regs.reg[2].loc.offset = (long)&sc->REG_NAME(edx) - new_cfa; 167227825Stheraven fs->regs.reg[6].how = REG_SAVED_OFFSET; 168227825Stheraven fs->regs.reg[6].loc.offset = (long)&sc->REG_NAME(esi) - new_cfa; 169227825Stheraven fs->regs.reg[7].how = REG_SAVED_OFFSET; 170227825Stheraven fs->regs.reg[7].loc.offset = (long)&sc->REG_NAME(edi) - new_cfa; 171227825Stheraven fs->regs.reg[5].how = REG_SAVED_OFFSET; 172227825Stheraven fs->regs.reg[5].loc.offset = (long)&sc->REG_NAME(ebp) - new_cfa; 173227825Stheraven fs->regs.reg[8].how = REG_SAVED_OFFSET; 174227825Stheraven fs->regs.reg[8].loc.offset = (long)&sc->REG_NAME(eip) - new_cfa; 175227825Stheraven fs->retaddr_column = 8; 176227825Stheraven fs->signal_frame = 1; 177227825Stheraven return _URC_NO_REASON; 178227825Stheraven} 179227825Stheraven#endif /* not glibc 2.0 */ 180227825Stheraven#endif /* ifdef __x86_64__ */ 181227825Stheraven#endif /* ifdef inhibit_libc */ 182227825Stheraven