Home | History | Annotate | Line # | Download | only in i386
freebsd-unwind.h revision 1.1.1.3
      1      1.1  mrg /* DWARF2 EH unwinding support for FreeBSD: AMD x86-64 and x86.
      2  1.1.1.2  mrg    Copyright (C) 2015-2016 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by John Marino <gnugcc (at) marino.st>
      4      1.1  mrg 
      5      1.1  mrg This file is part of GCC.
      6      1.1  mrg 
      7      1.1  mrg GCC is free software; you can redistribute it and/or modify
      8      1.1  mrg it under the terms of the GNU General Public License as published by
      9      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
     10      1.1  mrg any later version.
     11      1.1  mrg 
     12      1.1  mrg GCC is distributed in the hope that it will be useful,
     13      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  mrg GNU General Public License for more details.
     16      1.1  mrg 
     17      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     18      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     19      1.1  mrg 3.1, as published by the Free Software Foundation.
     20      1.1  mrg 
     21      1.1  mrg You should have received a copy of the GNU General Public License and
     22      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     23      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24      1.1  mrg <http://www.gnu.org/licenses/>.  */
     25      1.1  mrg 
     26      1.1  mrg /* Do code reading to identify a signal frame, and set the frame
     27      1.1  mrg    state data appropriately.  See unwind-dw2.c for the structs. */
     28      1.1  mrg 
     29      1.1  mrg #include <sys/types.h>
     30      1.1  mrg #include <signal.h>
     31  1.1.1.3  mrg #include <unistd.h>
     32  1.1.1.3  mrg #include <sys/sysctl.h>
     33      1.1  mrg #include <sys/ucontext.h>
     34  1.1.1.3  mrg #include <sys/user.h>
     35      1.1  mrg #include <machine/sigframe.h>
     36      1.1  mrg 
     37      1.1  mrg #define REG_NAME(reg)	sf_uc.uc_mcontext.mc_## reg
     38      1.1  mrg 
     39      1.1  mrg #ifdef __x86_64__
     40      1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_64_freebsd_fallback_frame_state
     41      1.1  mrg 
     42  1.1.1.3  mrg #ifdef KERN_PROC_SIGTRAMP
     43  1.1.1.3  mrg /* FreeBSD past 9.3 provides a kern.proc.sigtramp.<pid> sysctl that
     44  1.1.1.3  mrg    returns the location of the signal trampoline. Use this to find
     45  1.1.1.3  mrg    out whether we're in a trampoline.
     46  1.1.1.3  mrg */
     47  1.1.1.3  mrg static int
     48  1.1.1.3  mrg x86_64_outside_sigtramp_range (unsigned char *pc)
     49  1.1.1.3  mrg {
     50  1.1.1.3  mrg   static int sigtramp_range_determined = 0;
     51  1.1.1.3  mrg   static unsigned char *sigtramp_start, *sigtramp_end;
     52  1.1.1.3  mrg 
     53  1.1.1.3  mrg   if (sigtramp_range_determined == 0)
     54  1.1.1.3  mrg     {
     55  1.1.1.3  mrg       struct kinfo_sigtramp kst = {0};
     56  1.1.1.3  mrg       size_t len = sizeof (kst);
     57  1.1.1.3  mrg       int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid() };
     58  1.1.1.3  mrg 
     59  1.1.1.3  mrg       sigtramp_range_determined = 1;
     60  1.1.1.3  mrg       if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
     61  1.1.1.3  mrg       {
     62  1.1.1.3  mrg         sigtramp_range_determined = 2;
     63  1.1.1.3  mrg         sigtramp_start = kst.ksigtramp_start;
     64  1.1.1.3  mrg         sigtramp_end   = kst.ksigtramp_end;
     65  1.1.1.3  mrg       }
     66  1.1.1.3  mrg     }
     67  1.1.1.3  mrg   if (sigtramp_range_determined < 2)  /* sysctl failed if < 2 */
     68  1.1.1.3  mrg     return 1;
     69  1.1.1.3  mrg 
     70  1.1.1.3  mrg   return (pc < sigtramp_start || pc >= sigtramp_end);
     71  1.1.1.3  mrg }
     72  1.1.1.3  mrg #endif
     73  1.1.1.3  mrg 
     74      1.1  mrg static _Unwind_Reason_Code
     75      1.1  mrg x86_64_freebsd_fallback_frame_state
     76      1.1  mrg (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     77      1.1  mrg {
     78      1.1  mrg   struct sigframe *sf;
     79      1.1  mrg   long new_cfa;
     80      1.1  mrg 
     81  1.1.1.3  mrg #ifndef KERN_PROC_SIGTRAMP
     82      1.1  mrg   /* Prior to FreeBSD 9, the signal trampoline was located immediately
     83      1.1  mrg      before the ps_strings.  To support non-executable stacks on AMD64,
     84      1.1  mrg      the sigtramp was moved to a shared page for FreeBSD 9.  Unfortunately
     85      1.1  mrg      this means looking frame patterns again (sys/amd64/amd64/sigtramp.S)
     86      1.1  mrg      rather than using the robust and convenient KERN_PS_STRINGS trick.
     87      1.1  mrg 
     88      1.1  mrg      <pc + 00>:  lea     0x10(%rsp),%rdi
     89      1.1  mrg      <pc + 05>:  pushq   $0x0
     90      1.1  mrg      <pc + 17>:  mov     $0x1a1,%rax
     91      1.1  mrg      <pc + 14>:  syscall
     92      1.1  mrg 
     93      1.1  mrg      If we can't find this pattern, we're at the end of the stack.
     94      1.1  mrg   */
     95      1.1  mrg 
     96      1.1  mrg   if (!(   *(unsigned int *)(context->ra)      == 0x247c8d48
     97      1.1  mrg         && *(unsigned int *)(context->ra +  4) == 0x48006a10
     98      1.1  mrg         && *(unsigned int *)(context->ra +  8) == 0x01a1c0c7
     99      1.1  mrg         && *(unsigned int *)(context->ra + 12) == 0x050f0000 ))
    100      1.1  mrg     return _URC_END_OF_STACK;
    101  1.1.1.3  mrg #else
    102  1.1.1.3  mrg   if (x86_64_outside_sigtramp_range(context->ra))
    103  1.1.1.3  mrg     return _URC_END_OF_STACK;
    104  1.1.1.3  mrg #endif
    105      1.1  mrg 
    106      1.1  mrg   sf = (struct sigframe *) context->cfa;
    107      1.1  mrg   new_cfa = sf->REG_NAME(rsp);
    108      1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
    109  1.1.1.3  mrg   fs->regs.cfa_reg =  __LIBGCC_STACK_POINTER_REGNUM__;
    110      1.1  mrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
    111      1.1  mrg 
    112      1.1  mrg   /* The SVR4 register numbering macros aren't usable in libgcc.  */
    113      1.1  mrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
    114      1.1  mrg   fs->regs.reg[0].loc.offset = (long)&sf->REG_NAME(rax) - new_cfa;
    115      1.1  mrg   fs->regs.reg[1].how = REG_SAVED_OFFSET;
    116      1.1  mrg   fs->regs.reg[1].loc.offset = (long)&sf->REG_NAME(rdx) - new_cfa;
    117      1.1  mrg   fs->regs.reg[2].how = REG_SAVED_OFFSET;
    118      1.1  mrg   fs->regs.reg[2].loc.offset = (long)&sf->REG_NAME(rcx) - new_cfa;
    119      1.1  mrg   fs->regs.reg[3].how = REG_SAVED_OFFSET;
    120      1.1  mrg   fs->regs.reg[3].loc.offset = (long)&sf->REG_NAME(rbx) - new_cfa;
    121      1.1  mrg   fs->regs.reg[4].how = REG_SAVED_OFFSET;
    122      1.1  mrg   fs->regs.reg[4].loc.offset = (long)&sf->REG_NAME(rsi) - new_cfa;
    123      1.1  mrg   fs->regs.reg[5].how = REG_SAVED_OFFSET;
    124      1.1  mrg   fs->regs.reg[5].loc.offset = (long)&sf->REG_NAME(rdi) - new_cfa;
    125      1.1  mrg   fs->regs.reg[6].how = REG_SAVED_OFFSET;
    126      1.1  mrg   fs->regs.reg[6].loc.offset = (long)&sf->REG_NAME(rbp) - new_cfa;
    127      1.1  mrg   fs->regs.reg[8].how = REG_SAVED_OFFSET;
    128      1.1  mrg   fs->regs.reg[8].loc.offset = (long)&sf->REG_NAME(r8) - new_cfa;
    129      1.1  mrg   fs->regs.reg[9].how = REG_SAVED_OFFSET;
    130      1.1  mrg   fs->regs.reg[9].loc.offset = (long)&sf->REG_NAME(r9) - new_cfa;
    131      1.1  mrg   fs->regs.reg[10].how = REG_SAVED_OFFSET;
    132      1.1  mrg   fs->regs.reg[10].loc.offset = (long)&sf->REG_NAME(r10) - new_cfa;
    133      1.1  mrg   fs->regs.reg[11].how = REG_SAVED_OFFSET;
    134      1.1  mrg   fs->regs.reg[11].loc.offset = (long)&sf->REG_NAME(r11) - new_cfa;
    135      1.1  mrg   fs->regs.reg[12].how = REG_SAVED_OFFSET;
    136      1.1  mrg   fs->regs.reg[12].loc.offset = (long)&sf->REG_NAME(r12) - new_cfa;
    137      1.1  mrg   fs->regs.reg[13].how = REG_SAVED_OFFSET;
    138      1.1  mrg   fs->regs.reg[13].loc.offset = (long)&sf->REG_NAME(r13) - new_cfa;
    139      1.1  mrg   fs->regs.reg[14].how = REG_SAVED_OFFSET;
    140      1.1  mrg   fs->regs.reg[14].loc.offset = (long)&sf->REG_NAME(r14) - new_cfa;
    141      1.1  mrg   fs->regs.reg[15].how = REG_SAVED_OFFSET;
    142      1.1  mrg   fs->regs.reg[15].loc.offset = (long)&sf->REG_NAME(r15) - new_cfa;
    143      1.1  mrg   fs->regs.reg[16].how = REG_SAVED_OFFSET;
    144      1.1  mrg   fs->regs.reg[16].loc.offset = (long)&sf->REG_NAME(rip) - new_cfa;
    145      1.1  mrg   fs->retaddr_column = 16;
    146      1.1  mrg   fs->signal_frame = 1;
    147      1.1  mrg   return _URC_NO_REASON;
    148      1.1  mrg }
    149      1.1  mrg 
    150      1.1  mrg #else /* Next section is for i386  */
    151      1.1  mrg 
    152      1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR x86_freebsd_fallback_frame_state
    153      1.1  mrg 
    154      1.1  mrg /*
    155      1.1  mrg  * We can't use KERN_PS_STRINGS anymore if we want to support FreeBSD32
    156      1.1  mrg  * compat on AMD64.  The sigtramp is in a shared page in that case so the
    157      1.1  mrg  * x86_sigtramp_range only works on a true i386 system.  We have to
    158      1.1  mrg  * search for the sigtramp frame if we want it working everywhere.
    159      1.1  mrg  */
    160      1.1  mrg 
    161      1.1  mrg static _Unwind_Reason_Code
    162      1.1  mrg x86_freebsd_fallback_frame_state
    163      1.1  mrg (struct _Unwind_Context *context, _Unwind_FrameState *fs)
    164      1.1  mrg {
    165      1.1  mrg   struct sigframe *sf;
    166      1.1  mrg   long new_cfa;
    167      1.1  mrg 
    168      1.1  mrg /*
    169      1.1  mrg  * i386 sigtramp frame we are looking for follows.
    170      1.1  mrg  * Apparently PSL_VM is variable, so we can't look past context->ra + 4
    171      1.1  mrg  * <sigcode>:
    172      1.1  mrg  *   0:	ff 54 24 10          	call   *0x10(%esp)          *SIGF_HANDLER
    173      1.1  mrg  *   4:	8d 44 24 20          	lea    0x20(%esp),%eax       SIGF_UC
    174      1.1  mrg  *   8:	50                   	push   %eax
    175      1.1  mrg  *   9:	f7 40 54 00 00 02 00 	testl  $0x20000,0x54(%eax)  $PSL_VM
    176      1.1  mrg  *  10:	75 03                	jne    15 <sigcode+0x15>
    177      1.1  mrg  *  12:	8e 68 14             	mov    0x14(%eax),%gs        UC_GS
    178      1.1  mrg  *  15:	b8 a1 01 00 00       	mov    0x1a1,%eax           $SYS_sigreturn
    179      1.1  mrg  */
    180      1.1  mrg 
    181      1.1  mrg   if (!(   *(unsigned int *)(context->ra - 4) == 0x102454ff
    182      1.1  mrg         && *(unsigned int *)(context->ra)     == 0x2024448d ))
    183      1.1  mrg     return _URC_END_OF_STACK;
    184      1.1  mrg 
    185      1.1  mrg   sf = (struct sigframe *) context->cfa;
    186      1.1  mrg   new_cfa = sf->REG_NAME(esp);
    187      1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
    188      1.1  mrg   fs->regs.cfa_reg = 4;
    189      1.1  mrg   fs->regs.cfa_offset = new_cfa - (long) context->cfa;
    190      1.1  mrg 
    191      1.1  mrg   /* The SVR4 register numbering macros aren't usable in libgcc.  */
    192      1.1  mrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
    193      1.1  mrg   fs->regs.reg[0].loc.offset = (long)&sf->REG_NAME(eax) - new_cfa;
    194      1.1  mrg   fs->regs.reg[3].how = REG_SAVED_OFFSET;
    195      1.1  mrg   fs->regs.reg[3].loc.offset = (long)&sf->REG_NAME(ebx) - new_cfa;
    196      1.1  mrg   fs->regs.reg[1].how = REG_SAVED_OFFSET;
    197      1.1  mrg   fs->regs.reg[1].loc.offset = (long)&sf->REG_NAME(ecx) - new_cfa;
    198      1.1  mrg   fs->regs.reg[2].how = REG_SAVED_OFFSET;
    199      1.1  mrg   fs->regs.reg[2].loc.offset = (long)&sf->REG_NAME(edx) - new_cfa;
    200      1.1  mrg   fs->regs.reg[6].how = REG_SAVED_OFFSET;
    201      1.1  mrg   fs->regs.reg[6].loc.offset = (long)&sf->REG_NAME(esi) - new_cfa;
    202      1.1  mrg   fs->regs.reg[7].how = REG_SAVED_OFFSET;
    203      1.1  mrg   fs->regs.reg[7].loc.offset = (long)&sf->REG_NAME(edi) - new_cfa;
    204      1.1  mrg   fs->regs.reg[5].how = REG_SAVED_OFFSET;
    205      1.1  mrg   fs->regs.reg[5].loc.offset = (long)&sf->REG_NAME(ebp) - new_cfa;
    206      1.1  mrg   fs->regs.reg[8].how = REG_SAVED_OFFSET;
    207      1.1  mrg   fs->regs.reg[8].loc.offset = (long)&sf->REG_NAME(eip) - new_cfa;
    208      1.1  mrg   fs->retaddr_column = 8;
    209      1.1  mrg   fs->signal_frame = 1;
    210      1.1  mrg   return _URC_NO_REASON;
    211      1.1  mrg }
    212      1.1  mrg #endif /* ifdef __x86_64__  */
    213