Home | History | Annotate | Line # | Download | only in aarch64
      1 /* DWARF2 EH unwinding support for FreeBSD/ARM64 (aarch64).
      2    Copyright (C) 2017-2024 Free Software Foundation, Inc.
      3    Contributed by John Marino <gnugcc (at) 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 /* Identify a signal frame, and set the frame state data appropriately.
     27    See unwind-dw2.c for the structs. */
     28 
     29 /* Always include AArch64 unwinder header file.  */
     30 #include "config/aarch64/aarch64-unwind.h"
     31 
     32 #include <sys/types.h>
     33 #include <signal.h>
     34 #include <unistd.h>
     35 #include <sys/ucontext.h>
     36 #include <machine/frame.h>
     37 #include <sys/user.h>
     38 #include <sys/sysctl.h>
     39 
     40 #define REG_NAME(reg)   mc_gpregs.gp_## reg
     41 #define XREG(num)       mc_gpregs.gp_x[num]
     42 #define DARC            __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__
     43 
     44 #define MD_FALLBACK_FRAME_STATE_FOR aarch64_freebsd_fallback_frame_state
     45 
     46 static int
     47 aarch64_outside_sigtramp_range (unsigned char *pc)
     48 {
     49   static int sigtramp_range_determined = 0;
     50   static unsigned char *sigtramp_start, *sigtramp_end;
     51 
     52   if (sigtramp_range_determined == 0)
     53     {
     54       struct kinfo_sigtramp kst = {0};
     55       size_t len = sizeof (kst);
     56       int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid() };
     57 
     58       sigtramp_range_determined = 1;
     59       if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
     60       {
     61         sigtramp_range_determined = 2;
     62         sigtramp_start = kst.ksigtramp_start;
     63         sigtramp_end   = kst.ksigtramp_end;
     64       }
     65     }
     66   if (sigtramp_range_determined < 2)  /* sysctl failed if < 2 */
     67     return 1;
     68 
     69   return (pc < sigtramp_start || pc >= sigtramp_end);
     70 }
     71 
     72 static _Unwind_Reason_Code
     73 aarch64_freebsd_fallback_frame_state
     74 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     75 {
     76   int n;
     77   struct sigframe *sf;
     78   mcontext_t *sc;
     79   _Unwind_Ptr new_cfa;
     80 
     81   if (aarch64_outside_sigtramp_range(context->ra))
     82     return _URC_END_OF_STACK;
     83 
     84   sf = (struct sigframe *) context->cfa;
     85   sc = &sf->sf_uc.uc_mcontext;
     86 
     87   new_cfa = (_Unwind_Ptr) sc;
     88   fs->regs.cfa_how = CFA_REG_OFFSET;
     89   fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
     90   fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
     91 
     92   for (n = 0; n < 32; n++)
     93     fs->regs.how[n] = REG_SAVED_OFFSET;
     94 
     95   for (n = 0; n < 30; n++)
     96     fs->regs.reg[n].loc.offset = (_Unwind_Ptr) &(sc->XREG(n)) - new_cfa;
     97 
     98   fs->regs.reg[30].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(lr)) - new_cfa;
     99   fs->regs.reg[31].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(sp)) - new_cfa;
    100 
    101   fs->regs.how[DARC] = REG_SAVED_OFFSET;
    102   fs->regs.reg[DARC].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(elr)) - new_cfa;
    103 
    104   fs->retaddr_column = DARC;
    105   fs->signal_frame = 1;
    106 
    107   return _URC_NO_REASON;
    108 }
    109