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