1 /* DWARF2 EH unwinding support for Xtensa. 2 Copyright (C) 2008-2022 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GCC is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 Under Section 7 of GPL version 3, you are granted additional 17 permissions described in the GCC Runtime Library Exception, version 18 3.1, as published by the Free Software Foundation. 19 20 You should have received a copy of the GNU General Public License and 21 a copy of the GCC Runtime Library Exception along with this program; 22 see 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 57 static _Unwind_Reason_Code 58 xtensa_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