1 /* DWARF2 EH unwinding support for Xtensa.
2    Copyright (C) 2008-2021 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
xtensa_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)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