(root)/
gcc-13.2.0/
libgcc/
config/
nds32/
linux-unwind.h
       1  /* DWARF2 EH unwinding support for NDS32 Linux signal frame.
       2     Copyright (C) 2014-2023 Free Software Foundation, Inc.
       3     Contributed by Andes Technology Corporation.
       4  
       5     This file is part of GCC.
       6  
       7     GCC is free software; you can redistribute it and/or modify it
       8     under the terms of the GNU General Public License as published
       9     by the Free Software Foundation; either version 3, or (at your
      10     option) any later version.
      11  
      12     GCC is distributed in the hope that it will be useful, but WITHOUT
      13     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      14     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      15     License for more details.
      16  
      17     Under Section 7 of GPL version 3, you are granted additional
      18     permissions described in the GCC Runtime Library Exception, version
      19     3.1, as published by the Free Software Foundation.
      20  
      21     You should have received a copy of the GNU General Public License and
      22     a copy of the GCC Runtime Library Exception along with this program;
      23     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      24     <http://www.gnu.org/licenses/>.  */
      25  
      26  #ifndef inhibit_libc
      27  
      28  /* Do code reading to identify a signal frame, and set the frame
      29     state data appropriately.  See unwind-dw2.c for the structs.
      30     The corresponding bits in the Linux kernel are in
      31     arch/nds32/kernel/signal.c.  */
      32  
      33  #include <signal.h>
      34  #include <asm/unistd.h>
      35  #include <sys/ucontext.h>
      36  
      37  /* Exactly the same layout as the kernel structures, unique names.  */
      38  
      39  /* arch/nds32/kernel/signal.c */
      40  struct _rt_sigframe {
      41    siginfo_t info;
      42    struct ucontext_t uc;
      43  };
      44  
      45  #define RT_SIGRETURN 0x8b00f044
      46  
      47  #define MD_FALLBACK_FRAME_STATE_FOR nds32_fallback_frame_state
      48  
      49  /* This function is supposed to be invoked by uw_frame_state_for()
      50     when there is no unwind data available.
      51  
      52     Generally, given the _Unwind_Context CONTEXT for a stack frame,
      53     we need to look up its caller and decode information into FS.
      54     However, if the exception handling happens within a signal handler,
      55     the return address of signal handler is a special module, which
      56     contains signal return syscall and has no FDE in the .eh_frame section.
      57     We need to implement MD_FALLBACK_FRAME_STATE_FOR so that we can
      58     unwind through signal frames.  */
      59  static _Unwind_Reason_Code
      60  nds32_fallback_frame_state (struct _Unwind_Context *context,
      61  			    _Unwind_FrameState *fs)
      62  {
      63    u_int32_t *pc = (u_int32_t *) context->ra;
      64    struct sigcontext *sc_;
      65    _Unwind_Ptr new_cfa;
      66  
      67  #ifdef __NDS32_EB__
      68  #error "Signal handler is not supported for force unwind."
      69  #endif
      70  
      71    if ((_Unwind_Ptr) pc & 3)
      72      return _URC_END_OF_STACK;
      73  
      74    /* Check if we are going through a signal handler.
      75       See arch/nds32/kernel/signal.c implementation.
      76       FIXME: Currently we only handle little endian (EL) case.  */
      77    if (pc[0] == RT_SIGRETURN)
      78      {
      79        /* Using '_sigfame' memory address to locate kernal's sigcontext.
      80  	 The sigcontext structures in arch/nds32/include/asm/sigcontext.h.  */
      81        struct _rt_sigframe *rt_;
      82        rt_ = context->cfa;
      83        sc_ = &rt_->uc.uc_mcontext;
      84      }
      85    else
      86      return _URC_END_OF_STACK;
      87  
      88    /* Update cfa from sigcontext.  */
      89    new_cfa = (_Unwind_Ptr) sc_;
      90    fs->regs.cfa_how = CFA_REG_OFFSET;
      91    fs->regs.cfa_reg = STACK_POINTER_REGNUM;
      92    fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
      93  
      94  #define NDS32_PUT_FS_REG(NUM, NAME) \
      95    (fs->regs.how[NUM] = REG_SAVED_OFFSET, \
      96     fs->regs.reg[NUM].loc.offset = (_Unwind_Ptr) &(sc_->NAME) - new_cfa)
      97  
      98    /* Restore all registers value.  */
      99    NDS32_PUT_FS_REG (0, nds32_r0);
     100    NDS32_PUT_FS_REG (1, nds32_r1);
     101    NDS32_PUT_FS_REG (2, nds32_r2);
     102    NDS32_PUT_FS_REG (3, nds32_r3);
     103    NDS32_PUT_FS_REG (4, nds32_r4);
     104    NDS32_PUT_FS_REG (5, nds32_r5);
     105    NDS32_PUT_FS_REG (6, nds32_r6);
     106    NDS32_PUT_FS_REG (7, nds32_r7);
     107    NDS32_PUT_FS_REG (8, nds32_r8);
     108    NDS32_PUT_FS_REG (9, nds32_r9);
     109    NDS32_PUT_FS_REG (10, nds32_r10);
     110    NDS32_PUT_FS_REG (11, nds32_r11);
     111    NDS32_PUT_FS_REG (12, nds32_r12);
     112    NDS32_PUT_FS_REG (13, nds32_r13);
     113    NDS32_PUT_FS_REG (14, nds32_r14);
     114    NDS32_PUT_FS_REG (15, nds32_r15);
     115    NDS32_PUT_FS_REG (16, nds32_r16);
     116    NDS32_PUT_FS_REG (17, nds32_r17);
     117    NDS32_PUT_FS_REG (18, nds32_r18);
     118    NDS32_PUT_FS_REG (19, nds32_r19);
     119    NDS32_PUT_FS_REG (20, nds32_r20);
     120    NDS32_PUT_FS_REG (21, nds32_r21);
     121    NDS32_PUT_FS_REG (22, nds32_r22);
     122    NDS32_PUT_FS_REG (23, nds32_r23);
     123    NDS32_PUT_FS_REG (24, nds32_r24);
     124    NDS32_PUT_FS_REG (25, nds32_r25);
     125  
     126    NDS32_PUT_FS_REG (28, nds32_fp);
     127    NDS32_PUT_FS_REG (29, nds32_gp);
     128    NDS32_PUT_FS_REG (30, nds32_lp);
     129    NDS32_PUT_FS_REG (31, nds32_sp);
     130  
     131    /* Restore PC, point to trigger signal instruction.  */
     132    NDS32_PUT_FS_REG (32, nds32_ipc);
     133  
     134  #undef NDS32_PUT_FS_REG
     135  
     136    /* The retaddr is PC, use PC to find FDE.  */
     137    fs->retaddr_column = 32;
     138    fs->signal_frame = 1;
     139  
     140    return _URC_NO_REASON;
     141  }
     142  
     143  #endif