196263Sobrien/* DWARF2 EH unwinding support for FreeBSD/ARM64 (aarch64). 290075Sobrien Copyright (C) 2017-2020 Free Software Foundation, Inc. 390075Sobrien Contributed by John Marino <gnugcc@marino.st> 490075Sobrien 590075SobrienThis file is part of GCC. 690075Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify 890075Sobrienit under the terms of the GNU General Public License as published by 990075Sobrienthe Free Software Foundation; either version 3, or (at your option) 1090075Sobrienany later version. 1190075Sobrien 1290075SobrienGCC is distributed in the hope that it will be useful, 1390075Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1490075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1590075SobrienGNU General Public License for more details. 1690075Sobrien 1790075SobrienUnder Section 7 of GPL version 3, you are granted additional 1890075Sobrienpermissions described in the GCC Runtime Library Exception, version 1990075Sobrien3.1, as published by the Free Software Foundation. 2090075Sobrien 2190075SobrienYou should have received a copy of the GNU General Public License and 2290075Sobriena copy of the GCC Runtime Library Exception along with this program; 2390075Sobriensee the files COPYING3 and COPYING.RUNTIME respectively. If not, see 2490075Sobrien<http://www.gnu.org/licenses/>. */ 2590075Sobrien 2690075Sobrien/* Identify a signal frame, and set the frame state data appropriately. 2790075Sobrien See unwind-dw2.c for the structs. */ 2890075Sobrien 2990075Sobrien/* Always include AArch64 unwinder header file. */ 3090075Sobrien#include "config/aarch64/aarch64-unwind.h" 3190075Sobrien 3290075Sobrien#include <sys/types.h> 3390075Sobrien#include <signal.h> 3490075Sobrien#include <unistd.h> 3590075Sobrien#include <sys/ucontext.h> 3690075Sobrien#include <machine/frame.h> 3790075Sobrien#include <sys/user.h> 3890075Sobrien#include <sys/sysctl.h> 3990075Sobrien 4090075Sobrien#define REG_NAME(reg) mc_gpregs.gp_## reg 4190075Sobrien#define XREG(num) mc_gpregs.gp_x[num] 4290075Sobrien#define DARC __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__ 4390075Sobrien 4490075Sobrien#define MD_FALLBACK_FRAME_STATE_FOR aarch64_freebsd_fallback_frame_state 4590075Sobrien 4690075Sobrienstatic int 4790075Sobrienaarch64_outside_sigtramp_range (unsigned char *pc) 4890075Sobrien{ 4990075Sobrien static int sigtramp_range_determined = 0; 5090075Sobrien static unsigned char *sigtramp_start, *sigtramp_end; 5190075Sobrien 5290075Sobrien if (sigtramp_range_determined == 0) 5390075Sobrien { 5490075Sobrien struct kinfo_sigtramp kst = {0}; 5590075Sobrien size_t len = sizeof (kst); 5690075Sobrien int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid() }; 5790075Sobrien 5890075Sobrien sigtramp_range_determined = 1; 5990075Sobrien if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0) 6090075Sobrien { 6190075Sobrien sigtramp_range_determined = 2; 6290075Sobrien sigtramp_start = kst.ksigtramp_start; 6390075Sobrien sigtramp_end = kst.ksigtramp_end; 6490075Sobrien } 6590075Sobrien } 6690075Sobrien if (sigtramp_range_determined < 2) /* sysctl failed if < 2 */ 6790075Sobrien return 1; 6890075Sobrien 6990075Sobrien return (pc < sigtramp_start || pc >= sigtramp_end); 7090075Sobrien} 7190075Sobrien 7290075Sobrienstatic _Unwind_Reason_Code 7390075Sobrienaarch64_freebsd_fallback_frame_state 7490075Sobrien(struct _Unwind_Context *context, _Unwind_FrameState *fs) 7590075Sobrien{ 7690075Sobrien int n; 7790075Sobrien struct sigframe *sf; 7890075Sobrien mcontext_t *sc; 7990075Sobrien _Unwind_Ptr new_cfa; 8090075Sobrien 8190075Sobrien if (aarch64_outside_sigtramp_range(context->ra)) 8290075Sobrien return _URC_END_OF_STACK; 8390075Sobrien 8490075Sobrien sf = (struct sigframe *) context->cfa; 8590075Sobrien sc = &sf->sf_uc.uc_mcontext; 8690075Sobrien 8790075Sobrien new_cfa = (_Unwind_Ptr) sc; 8890075Sobrien fs->regs.cfa_how = CFA_REG_OFFSET; 8990075Sobrien fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__; 9090075Sobrien fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; 9190075Sobrien 9290075Sobrien for (n = 0; n < 32; n++) 9390075Sobrien fs->regs.reg[n].how = REG_SAVED_OFFSET; 9490075Sobrien 9590075Sobrien for (n = 0; n < 30; n++) 9690075Sobrien fs->regs.reg[n].loc.offset = (_Unwind_Ptr) &(sc->XREG(n)) - new_cfa; 9790075Sobrien 9890075Sobrien fs->regs.reg[30].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(lr)) - new_cfa; 9990075Sobrien fs->regs.reg[31].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(sp)) - new_cfa; 10090075Sobrien 10190075Sobrien fs->regs.reg[DARC].how = REG_SAVED_OFFSET; 10290075Sobrien fs->regs.reg[DARC].loc.offset = (_Unwind_Ptr) &(sc->REG_NAME(elr)) - new_cfa; 10390075Sobrien 10490075Sobrien fs->retaddr_column = DARC; 10590075Sobrien fs->signal_frame = 1; 10690075Sobrien 10790075Sobrien return _URC_NO_REASON; 10890075Sobrien} 10990075Sobrien