1*0bfacb9bSmrg /* Copyright (C) 2016-2020 Free Software Foundation, Inc.
2ac8e35e1Smrg 
3ac8e35e1Smrg    This file is free software; you can redistribute it and/or modify it
4ac8e35e1Smrg    under the terms of the GNU General Public License as published by the
5ac8e35e1Smrg    Free Software Foundation; either version 3, or (at your option) any
6ac8e35e1Smrg    later version.
7ac8e35e1Smrg 
8ac8e35e1Smrg    This file is distributed in the hope that it will be useful, but
9ac8e35e1Smrg    WITHOUT ANY WARRANTY; without even the implied warranty of
10ac8e35e1Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11ac8e35e1Smrg    General Public License for more details.
12ac8e35e1Smrg 
13ac8e35e1Smrg    Under Section 7 of GPL version 3, you are granted additional
14ac8e35e1Smrg    permissions described in the GCC Runtime Library Exception, version
15ac8e35e1Smrg    3.1, as published by the Free Software Foundation.
16ac8e35e1Smrg 
17ac8e35e1Smrg    You should have received a copy of the GNU General Public License and
18ac8e35e1Smrg    a copy of the GCC Runtime Library Exception along with this program;
19ac8e35e1Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
20ac8e35e1Smrg    <http://www.gnu.org/licenses/>.  */
21ac8e35e1Smrg 
22ac8e35e1Smrg #ifndef inhibit_libc
23ac8e35e1Smrg 
24ac8e35e1Smrg #include <signal.h>
25ac8e35e1Smrg #include <stdint.h>
26ac8e35e1Smrg #include <sys/ucontext.h>
27ac8e35e1Smrg 
28ac8e35e1Smrg #define LI_A7_8B 0x08b00893
29ac8e35e1Smrg #define ECALL    0x00000073
30ac8e35e1Smrg 
31ac8e35e1Smrg #define MD_FALLBACK_FRAME_STATE_FOR riscv_fallback_frame_state
32ac8e35e1Smrg 
33ac8e35e1Smrg static _Unwind_Reason_Code
riscv_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)34ac8e35e1Smrg riscv_fallback_frame_state (struct _Unwind_Context *context,
35ac8e35e1Smrg 			    _Unwind_FrameState * fs)
36ac8e35e1Smrg {
37ac8e35e1Smrg   /* The kernel creates an rt_sigframe on the stack immediately prior
38ac8e35e1Smrg      to delivering a signal.
39ac8e35e1Smrg 
40ac8e35e1Smrg      This structure must have the same shape as the linux kernel
41ac8e35e1Smrg      equivalent.  */
42ac8e35e1Smrg   struct rt_sigframe
43ac8e35e1Smrg   {
44ac8e35e1Smrg     siginfo_t info;
45ac8e35e1Smrg     ucontext_t uc;
46ac8e35e1Smrg   };
47ac8e35e1Smrg 
48ac8e35e1Smrg   struct rt_sigframe *rt_;
49ac8e35e1Smrg   _Unwind_Ptr new_cfa;
50ac8e35e1Smrg   uint16_t *pc = context->ra;
51ac8e35e1Smrg   struct sigcontext *sc;
52ac8e35e1Smrg   int i;
53ac8e35e1Smrg 
54ac8e35e1Smrg   /* A signal frame will have a return address pointing to
55ac8e35e1Smrg      __default_sa_restorer. This code is hardwired as:
56ac8e35e1Smrg 
57ac8e35e1Smrg      0x08b00893		li	a7,0x8b
58ac8e35e1Smrg      0x00000073		ecall
59ac8e35e1Smrg 
60ac8e35e1Smrg      Note, the PC might only have 2-byte alignment.
61ac8e35e1Smrg    */
62ac8e35e1Smrg   if (pc[0] != (uint16_t)LI_A7_8B || pc[1] != (uint16_t)(LI_A7_8B >> 16)
63ac8e35e1Smrg       || pc[2] != (uint16_t)ECALL || pc[3] != (uint16_t)(ECALL >> 16))
64ac8e35e1Smrg     return _URC_END_OF_STACK;
65ac8e35e1Smrg 
66ac8e35e1Smrg   rt_ = context->cfa;
67ac8e35e1Smrg   sc = &rt_->uc.uc_mcontext;
68ac8e35e1Smrg 
69ac8e35e1Smrg   new_cfa = (_Unwind_Ptr) sc;
70ac8e35e1Smrg   fs->regs.cfa_how = CFA_REG_OFFSET;
71ac8e35e1Smrg   fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__;
72ac8e35e1Smrg   fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
73ac8e35e1Smrg 
74ac8e35e1Smrg   for (i = 0; i < 32; i++)
75ac8e35e1Smrg     {
76ac8e35e1Smrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
77ac8e35e1Smrg       fs->regs.reg[i].loc.offset = (_Unwind_Ptr) &sc->gregs[i] - new_cfa;
78ac8e35e1Smrg     }
79ac8e35e1Smrg 
80ac8e35e1Smrg   fs->signal_frame = 1;
81ac8e35e1Smrg   fs->retaddr_column = __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__;
82ac8e35e1Smrg   fs->regs.reg[fs->retaddr_column].how = REG_SAVED_VAL_OFFSET;
83ac8e35e1Smrg   fs->regs.reg[fs->retaddr_column].loc.offset =
84ac8e35e1Smrg     (_Unwind_Ptr) sc->gregs[0] - new_cfa;
85ac8e35e1Smrg 
86ac8e35e1Smrg   return _URC_NO_REASON;
87ac8e35e1Smrg }
88ac8e35e1Smrg 
89ac8e35e1Smrg #endif
90