Home | History | Annotate | Line # | Download | only in i386
      1       1.1  mrg /* DWARF2 EH unwinding support for AMD x86-64 and x86.
      2  1.1.1.13  mrg    Copyright (C) 2004-2024 Free Software Foundation, Inc.
      3       1.1  mrg 
      4       1.1  mrg This file is part of GCC.
      5       1.1  mrg 
      6       1.1  mrg GCC is free software; you can redistribute it and/or modify
      7       1.1  mrg it under the terms of the GNU General Public License as published by
      8       1.1  mrg the Free Software Foundation; either version 3, or (at your option)
      9       1.1  mrg any later version.
     10       1.1  mrg 
     11       1.1  mrg GCC is distributed in the hope that it will be useful,
     12       1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     13       1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14       1.1  mrg GNU General Public License for more details.
     15       1.1  mrg 
     16       1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     17       1.1  mrg permissions described in the GCC Runtime Library Exception, version
     18       1.1  mrg 3.1, as published by the Free Software Foundation.
     19       1.1  mrg 
     20       1.1  mrg You should have received a copy of the GNU General Public License and
     21       1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     22       1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23       1.1  mrg <http://www.gnu.org/licenses/>.  */
     24       1.1  mrg 
     25   1.1.1.9  mrg /* Unwind shadow stack for -fcf-protection -mshstk.  */
     26   1.1.1.9  mrg #if defined __SHSTK__ && defined __CET__ && (__CET__ & 2) != 0
     27   1.1.1.9  mrg # include "config/i386/shadow-stack-unwind.h"
     28   1.1.1.9  mrg #endif
     29   1.1.1.9  mrg 
     30       1.1  mrg /* Do code reading to identify a signal frame, and set the frame
     31       1.1  mrg    state data appropriately.  See unwind-dw2.c for the structs.
     32       1.1  mrg    Don't use this at all if inhibit_libc is used.  */
     33       1.1  mrg 
     34       1.1  mrg #ifndef inhibit_libc
     35       1.1  mrg 
     36       1.1  mrg /* There's no sys/ucontext.h for glibc 2.0, so no
     37       1.1  mrg    signal-turned-exceptions for them.  There's also no configure-run for
     38       1.1  mrg    the target, so we can't check on (e.g.) HAVE_SYS_UCONTEXT_H.  Using the
     39       1.1  mrg    target libc version macro should be enough.  */
     40       1.1  mrg #if defined __GLIBC__ && !(__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
     41       1.1  mrg 
     42       1.1  mrg #include <signal.h>
     43       1.1  mrg #include <sys/ucontext.h>
     44       1.1  mrg 
     45       1.1  mrg #ifdef __x86_64__
     46       1.1  mrg 
     47       1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state
     48       1.1  mrg 
     49       1.1  mrg static _Unwind_Reason_Code
     50       1.1  mrg x86_64_fallback_frame_state (struct _Unwind_Context *context,
     51       1.1  mrg 			     _Unwind_FrameState *fs)
     52       1.1  mrg {
     53       1.1  mrg   unsigned char *pc = context->ra;
     54       1.1  mrg   struct sigcontext *sc;
     55       1.1  mrg   long new_cfa;
     56       1.1  mrg 
     57       1.1  mrg   /* movq $__NR_rt_sigreturn, %rax ; syscall.  */
     58       1.1  mrg #ifdef __LP64__
     59       1.1  mrg #define RT_SIGRETURN_SYSCALL	0x050f0000000fc0c7ULL
     60       1.1  mrg #else
     61       1.1  mrg #define RT_SIGRETURN_SYSCALL	0x050f40000201c0c7ULL
     62       1.1  mrg #endif
     63       1.1  mrg   if (*(unsigned char *)(pc+0) == 0x48
     64       1.1  mrg       && *(unsigned long long *)(pc+1) == RT_SIGRETURN_SYSCALL)
     65       1.1  mrg     {
     66   1.1.1.5  mrg       ucontext_t *uc_ = context->cfa;
     67       1.1  mrg       /* The void * cast is necessary to avoid an aliasing warning.
     68       1.1  mrg          The aliasing warning is correct, but should not be a problem
     69       1.1  mrg          because it does not alias anything.  */
     70       1.1  mrg       sc = (struct sigcontext *) (void *) &uc_->uc_mcontext;
     71       1.1  mrg     }
     72       1.1  mrg   else
     73       1.1  mrg     return _URC_END_OF_STACK;
     74       1.1  mrg 
     75       1.1  mrg   new_cfa = sc->rsp;
     76       1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
     77       1.1  mrg   /* Register 7 is rsp  */
     78       1.1  mrg   fs->regs.cfa_reg = 7;
     79       1.1  mrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
     80       1.1  mrg 
     81       1.1  mrg   /* The SVR4 register numbering macros aren't usable in libgcc.  */
     82  1.1.1.13  mrg   fs->regs.how[0] = REG_SAVED_OFFSET;
     83       1.1  mrg   fs->regs.reg[0].loc.offset = (long)&sc->rax - new_cfa;
     84  1.1.1.13  mrg   fs->regs.how[1] = REG_SAVED_OFFSET;
     85       1.1  mrg   fs->regs.reg[1].loc.offset = (long)&sc->rdx - new_cfa;
     86  1.1.1.13  mrg   fs->regs.how[2] = REG_SAVED_OFFSET;
     87       1.1  mrg   fs->regs.reg[2].loc.offset = (long)&sc->rcx - new_cfa;
     88  1.1.1.13  mrg   fs->regs.how[3] = REG_SAVED_OFFSET;
     89       1.1  mrg   fs->regs.reg[3].loc.offset = (long)&sc->rbx - new_cfa;
     90  1.1.1.13  mrg   fs->regs.how[4] = REG_SAVED_OFFSET;
     91       1.1  mrg   fs->regs.reg[4].loc.offset = (long)&sc->rsi - new_cfa;
     92  1.1.1.13  mrg   fs->regs.how[5] = REG_SAVED_OFFSET;
     93       1.1  mrg   fs->regs.reg[5].loc.offset = (long)&sc->rdi - new_cfa;
     94  1.1.1.13  mrg   fs->regs.how[6] = REG_SAVED_OFFSET;
     95       1.1  mrg   fs->regs.reg[6].loc.offset = (long)&sc->rbp - new_cfa;
     96  1.1.1.13  mrg   fs->regs.how[8] = REG_SAVED_OFFSET;
     97       1.1  mrg   fs->regs.reg[8].loc.offset = (long)&sc->r8 - new_cfa;
     98  1.1.1.13  mrg   fs->regs.how[9] = REG_SAVED_OFFSET;
     99       1.1  mrg   fs->regs.reg[9].loc.offset = (long)&sc->r9 - new_cfa;
    100  1.1.1.13  mrg   fs->regs.how[10] = REG_SAVED_OFFSET;
    101       1.1  mrg   fs->regs.reg[10].loc.offset = (long)&sc->r10 - new_cfa;
    102  1.1.1.13  mrg   fs->regs.how[11] = REG_SAVED_OFFSET;
    103       1.1  mrg   fs->regs.reg[11].loc.offset = (long)&sc->r11 - new_cfa;
    104  1.1.1.13  mrg   fs->regs.how[12] = REG_SAVED_OFFSET;
    105       1.1  mrg   fs->regs.reg[12].loc.offset = (long)&sc->r12 - new_cfa;
    106  1.1.1.13  mrg   fs->regs.how[13] = REG_SAVED_OFFSET;
    107       1.1  mrg   fs->regs.reg[13].loc.offset = (long)&sc->r13 - new_cfa;
    108  1.1.1.13  mrg   fs->regs.how[14] = REG_SAVED_OFFSET;
    109       1.1  mrg   fs->regs.reg[14].loc.offset = (long)&sc->r14 - new_cfa;
    110  1.1.1.13  mrg   fs->regs.how[15] = REG_SAVED_OFFSET;
    111       1.1  mrg   fs->regs.reg[15].loc.offset = (long)&sc->r15 - new_cfa;
    112  1.1.1.13  mrg   fs->regs.how[16] = REG_SAVED_OFFSET;
    113       1.1  mrg   fs->regs.reg[16].loc.offset = (long)&sc->rip - new_cfa;
    114       1.1  mrg   fs->retaddr_column = 16;
    115       1.1  mrg   fs->signal_frame = 1;
    116       1.1  mrg   return _URC_NO_REASON;
    117       1.1  mrg }
    118       1.1  mrg 
    119       1.1  mrg #else /* ifdef __x86_64__  */
    120       1.1  mrg 
    121       1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state
    122       1.1  mrg 
    123       1.1  mrg static _Unwind_Reason_Code
    124       1.1  mrg x86_fallback_frame_state (struct _Unwind_Context *context,
    125       1.1  mrg 			  _Unwind_FrameState *fs)
    126       1.1  mrg {
    127       1.1  mrg   unsigned char *pc = context->ra;
    128       1.1  mrg   struct sigcontext *sc;
    129       1.1  mrg   long new_cfa;
    130       1.1  mrg 
    131       1.1  mrg   /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80  */
    132       1.1  mrg   if (*(unsigned short *)(pc+0) == 0xb858
    133       1.1  mrg       && *(unsigned int *)(pc+2) == 119
    134       1.1  mrg       && *(unsigned short *)(pc+6) == 0x80cd)
    135       1.1  mrg     sc = context->cfa + 4;
    136       1.1  mrg   /* movl $__NR_rt_sigreturn,%eax ; int $0x80  */
    137       1.1  mrg   else if (*(unsigned char *)(pc+0) == 0xb8
    138       1.1  mrg 	   && *(unsigned int *)(pc+1) == 173
    139       1.1  mrg 	   && *(unsigned short *)(pc+5) == 0x80cd)
    140       1.1  mrg     {
    141       1.1  mrg       struct rt_sigframe {
    142       1.1  mrg 	int sig;
    143       1.1  mrg 	siginfo_t *pinfo;
    144       1.1  mrg 	void *puc;
    145       1.1  mrg 	siginfo_t info;
    146   1.1.1.5  mrg 	ucontext_t uc;
    147       1.1  mrg       } *rt_ = context->cfa;
    148       1.1  mrg       /* The void * cast is necessary to avoid an aliasing warning.
    149       1.1  mrg          The aliasing warning is correct, but should not be a problem
    150       1.1  mrg          because it does not alias anything.  */
    151       1.1  mrg       sc = (struct sigcontext *) (void *) &rt_->uc.uc_mcontext;
    152       1.1  mrg     }
    153       1.1  mrg   else
    154       1.1  mrg     return _URC_END_OF_STACK;
    155       1.1  mrg 
    156       1.1  mrg   new_cfa = sc->esp;
    157       1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
    158       1.1  mrg   fs->regs.cfa_reg = 4;
    159       1.1  mrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
    160       1.1  mrg 
    161       1.1  mrg   /* The SVR4 register numbering macros aren't usable in libgcc.  */
    162  1.1.1.13  mrg   fs->regs.how[0] = REG_SAVED_OFFSET;
    163       1.1  mrg   fs->regs.reg[0].loc.offset = (long)&sc->eax - new_cfa;
    164  1.1.1.13  mrg   fs->regs.how[3] = REG_SAVED_OFFSET;
    165       1.1  mrg   fs->regs.reg[3].loc.offset = (long)&sc->ebx - new_cfa;
    166  1.1.1.13  mrg   fs->regs.how[1] = REG_SAVED_OFFSET;
    167       1.1  mrg   fs->regs.reg[1].loc.offset = (long)&sc->ecx - new_cfa;
    168  1.1.1.13  mrg   fs->regs.how[2] = REG_SAVED_OFFSET;
    169       1.1  mrg   fs->regs.reg[2].loc.offset = (long)&sc->edx - new_cfa;
    170  1.1.1.13  mrg   fs->regs.how[6] = REG_SAVED_OFFSET;
    171       1.1  mrg   fs->regs.reg[6].loc.offset = (long)&sc->esi - new_cfa;
    172  1.1.1.13  mrg   fs->regs.how[7] = REG_SAVED_OFFSET;
    173       1.1  mrg   fs->regs.reg[7].loc.offset = (long)&sc->edi - new_cfa;
    174  1.1.1.13  mrg   fs->regs.how[5] = REG_SAVED_OFFSET;
    175       1.1  mrg   fs->regs.reg[5].loc.offset = (long)&sc->ebp - new_cfa;
    176  1.1.1.13  mrg   fs->regs.how[8] = REG_SAVED_OFFSET;
    177       1.1  mrg   fs->regs.reg[8].loc.offset = (long)&sc->eip - new_cfa;
    178       1.1  mrg   fs->retaddr_column = 8;
    179       1.1  mrg   fs->signal_frame = 1;
    180       1.1  mrg   return _URC_NO_REASON;
    181       1.1  mrg }
    182       1.1  mrg 
    183       1.1  mrg #define MD_FROB_UPDATE_CONTEXT x86_frob_update_context
    184       1.1  mrg 
    185       1.1  mrg /* Fix up for kernels that have vDSO, but don't have S flag in it.  */
    186       1.1  mrg 
    187       1.1  mrg static void
    188       1.1  mrg x86_frob_update_context (struct _Unwind_Context *context,
    189       1.1  mrg 			 _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
    190       1.1  mrg {
    191       1.1  mrg   unsigned char *pc = context->ra;
    192       1.1  mrg 
    193       1.1  mrg   /* movl $__NR_rt_sigreturn,%eax ; {int $0x80 | syscall}  */
    194       1.1  mrg   if (*(unsigned char *)(pc+0) == 0xb8
    195       1.1  mrg       && *(unsigned int *)(pc+1) == 173
    196       1.1  mrg       && (*(unsigned short *)(pc+5) == 0x80cd
    197       1.1  mrg 	  || *(unsigned short *)(pc+5) == 0x050f))
    198       1.1  mrg     _Unwind_SetSignalFrame (context, 1);
    199       1.1  mrg }
    200       1.1  mrg 
    201       1.1  mrg #endif /* ifdef __x86_64__  */
    202       1.1  mrg #endif /* not glibc 2.0 */
    203       1.1  mrg #endif /* ifdef inhibit_libc  */
    204