1/* DWARF2 EH unwinding support for Xtensa. 2 Copyright (C) 2008-2022 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 3, or (at your option) 9any later version. 10 11GCC is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16Under Section 7 of GPL version 3, you are granted additional 17permissions described in the GCC Runtime Library Exception, version 183.1, as published by the Free Software Foundation. 19 20You should have received a copy of the GNU General Public License and 21a copy of the GCC Runtime Library Exception along with this program; 22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23<http://www.gnu.org/licenses/>. */ 24 25/* Do code reading to identify a signal frame, and set the frame 26 state data appropriately. See unwind-dw2-xtensa.c for the structs. 27 Don't use this at all if inhibit_libc is used. */ 28 29#ifndef inhibit_libc 30 31#include <signal.h> 32#include <sys/ucontext.h> 33 34/* Encoded bytes for Xtensa instructions: 35 movi a2, __NR_rt_sigreturn 36 syscall 37 entry (first byte only) 38 Some of the bytes are endian-dependent. */ 39 40#define MOVI_BYTE0 0x22 41#define MOVI_BYTE2 225 /* __NR_rt_sigreturn */ 42#define SYSC_BYTE0 0 43#define SYSC_BYTE2 0 44 45#ifdef __XTENSA_EB__ 46#define MOVI_BYTE1 0x0a 47#define SYSC_BYTE1 0x05 48#define ENTRY_BYTE 0x6c 49#else 50#define MOVI_BYTE1 0xa0 51#define SYSC_BYTE1 0x50 52#define ENTRY_BYTE 0x36 53#endif 54 55#define MD_FALLBACK_FRAME_STATE_FOR xtensa_fallback_frame_state 56 57static _Unwind_Reason_Code 58xtensa_fallback_frame_state (struct _Unwind_Context *context, 59 _Unwind_FrameState *fs) 60{ 61 unsigned char *pc = context->ra; 62 struct sigcontext *sc; 63#if defined(__XTENSA_CALL0_ABI__) 64 _Unwind_Ptr new_cfa; 65 int i; 66#endif 67 68 struct rt_sigframe { 69 siginfo_t info; 70 ucontext_t uc; 71 } *rt_; 72 73 /* movi a2, __NR_rt_sigreturn; syscall */ 74 if (pc[0] != MOVI_BYTE0 75 || pc[1] != MOVI_BYTE1 76 || pc[2] != MOVI_BYTE2 77 || pc[3] != SYSC_BYTE0 78 || pc[4] != SYSC_BYTE1 79 || pc[5] != SYSC_BYTE2) 80 return _URC_END_OF_STACK; 81 82#if defined(__XTENSA_WINDOWED_ABI__) 83 rt_ = context->sp; 84 sc = &rt_->uc.uc_mcontext; 85 fs->signal_regs = (_Unwind_Word *) sc->sc_a; 86 87 /* If the signal arrived just before an ENTRY instruction, find the return 88 address and pretend the signal arrived before executing the CALL. */ 89 if (*(unsigned char *) sc->sc_pc == ENTRY_BYTE) 90 { 91 unsigned callinc = (sc->sc_ps >> 16) & 3; 92 fs->signal_ra = ((sc->sc_a[callinc << 2] & XTENSA_RA_FIELD_MASK) 93 | context->ra_high_bits) - 3; 94 } 95 else 96 fs->signal_ra = sc->sc_pc; 97#elif defined(__XTENSA_CALL0_ABI__) 98 rt_ = context->cfa; 99 sc = &rt_->uc.uc_mcontext; 100 101 new_cfa = (_Unwind_Ptr) sc; 102 fs->regs.cfa_how = CFA_REG_OFFSET; 103 fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__; 104 fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; 105 106 for (i = 0; i < 16; i++) 107 { 108 fs->regs.reg[i].how = REG_SAVED_OFFSET; 109 fs->regs.reg[i].loc.offset = (_Unwind_Ptr) &(sc->sc_a[i]) - new_cfa; 110 } 111 112 fs->regs.reg[__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__].how = 113 REG_SAVED_VAL_OFFSET; 114 fs->regs.reg[__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__].loc.offset = 115 (_Unwind_Ptr) (sc->sc_pc) - new_cfa; 116 fs->retaddr_column = __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__; 117#else 118#error Unsupported Xtensa ABI 119#endif 120 121 fs->signal_frame = 1; 122 return _URC_NO_REASON; 123} 124 125 126#endif /* ifdef inhibit_libc */ 127