1/* DWARF2 EH unwinding support for FreeBSD/ARM64 (aarch64). 2 Copyright (C) 2017-2020 Free Software Foundation, Inc. 3 Contributed by John Marino <gnugcc@marino.st> 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3, or (at your option) 10any later version. 11 12GCC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see 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 46static int 47aarch64_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 72static _Unwind_Reason_Code 73aarch64_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.reg[n].how = 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.reg[DARC].how = 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