(root)/
gcc-13.2.0/
libgcc/
config/
sparc/
sol2-unwind.h
       1  /* DWARF2 EH unwinding support for SPARC Solaris.
       2     Copyright (C) 2009-2023 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.c for the structs.  */
      27  
      28  #include <ucontext.h>
      29  #include <sys/frame.h>
      30  #include <sys/stack.h>
      31  
      32  #ifdef __arch64__
      33  
      34  #define IS_SIGHANDLER sparc64_is_sighandler
      35  
      36  static int
      37  sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
      38  {
      39    if (/* Solaris 8+ - multi-threaded
      40  	----------------------------
      41  	<__sighndlr>:        save  %sp, -176, %sp
      42  	<__sighndlr+4>:      mov  %i0, %o0
      43  	<__sighndlr+8>:      mov  %i1, %o1
      44  	<__sighndlr+12>:     call  %i3
      45  	<__sighndlr+16>:     mov  %i2, %o2
      46  	<__sighndlr+20>:     ret 		<--- PC
      47  	<__sighndlr+24>:     restore  */
      48           pc[-5] == 0x9de3bf50
      49        && pc[-4] == 0x90100018
      50        && pc[-3] == 0x92100019
      51        && pc[-2] == 0x9fc6c000
      52        && pc[-1] == 0x9410001a
      53        && pc[ 0] == 0x81c7e008
      54        && pc[ 1] == 0x81e80000)
      55      {
      56        /* We have observed different calling frames among different
      57  	 versions of the operating system, so that we need to
      58  	 discriminate using the upper frame.  We look for the return
      59  	 address of the caller frame (there is an offset of 15 double
      60  	 words between the frame address and the place where this return
      61  	 address is stored) in order to do some more pattern matching.  */
      62        unsigned int cuh_pattern
      63  	= *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4);
      64  
      65        if (cuh_pattern == 0x92100019)
      66  	/* This matches the call_user_handler pattern in Solaris 11
      67  	   libc.so.1:
      68  
      69  	   <call_user_handler+864>:     mov  %i1, %o1
      70  	   <call_user_handler+868>:     call __sighndlr  */
      71  	*nframes = 3;
      72  
      73        return 1;
      74      }
      75  
      76    return 0;
      77  }
      78  
      79  #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
      80  
      81  #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
      82  
      83  static void
      84  sparc64_frob_update_context (struct _Unwind_Context *context,
      85  			     _Unwind_FrameState *fs)
      86  {
      87    /* The column of %sp contains the old CFA, not the old value of %sp.
      88       The CFA offset already comprises the stack bias so, when %sp is the
      89       CFA register, we must avoid counting the stack bias twice.  */
      90    if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
      91        && fs->regs.cfa_how == CFA_REG_OFFSET
      92        && fs->regs.cfa_offset != 0)
      93      {
      94        long i;
      95  
      96        context->cfa -= STACK_BIAS;
      97  
      98        for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
      99  	if (fs->regs.how[i] == REG_SAVED_OFFSET)
     100  	  _Unwind_SetGRPtr (context, i,
     101  			    _Unwind_GetGRPtr (context, i) - STACK_BIAS);
     102      }
     103  }
     104  
     105  #else
     106  
     107  #define IS_SIGHANDLER sparc_is_sighandler
     108  
     109  static int
     110  sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
     111  {
     112    if(/* Solaris 8+ - multi-threaded
     113         ----------------------------
     114         <__sighndlr>:	save  %sp, -96, %sp
     115         <__sighndlr+4>:	mov  %i0, %o0
     116         <__sighndlr+8>:	mov  %i1, %o1
     117         <__sighndlr+12>:	call  %i3
     118         <__sighndlr+16>:	mov  %i2, %o2
     119         <__sighndlr+20>:	ret 		<--- PC
     120         <__sighndlr+24>:	restore  */
     121          pc[-5] == 0x9de3bfa0
     122       && pc[-4] == 0x90100018
     123       && pc[-3] == 0x92100019
     124       && pc[-2] == 0x9fc6c000
     125       && pc[-1] == 0x9410001a
     126       && pc[ 0] == 0x81c7e008
     127       && pc[ 1] == 0x81e80000)
     128      {
     129        /* We have observed different calling frames among different
     130  	 versions of the operating system, so that we need to
     131  	 discriminate using the upper frame.  We look for the return
     132  	 address of the caller frame (there is an offset of 15 words
     133  	 between the frame address and the place where this return
     134  	 address is stored) in order to do some more pattern matching.  */
     135        unsigned int cuh_pattern
     136  	= *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4);
     137  
     138        if (cuh_pattern == 0x92100019)
     139  	/* This matches the call_user_handler pattern in Solaris 11
     140  	   libc.so.1:
     141  
     142  	   <call_user_handler+876>:     mov  %i1, %o1
     143  	   <call_user_handler+880>:     call __sighndlr  */
     144  	*nframes = 3;
     145  
     146        return 1;
     147      }
     148  
     149    return 0;
     150  }
     151  
     152  #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
     153  
     154  #endif
     155  
     156  static _Unwind_Reason_Code
     157  MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
     158  			     _Unwind_FrameState *fs)
     159  {
     160    void *pc = context->ra;
     161    void *this_cfa = context->cfa;
     162    int nframes = 0;
     163    long new_cfa;
     164    void *ra_location, *shifted_ra_location;
     165    mcontext_t *mctx;
     166    int i;
     167  
     168    /* Deal with frame-less function from which a signal was raised.  */
     169    if (_Unwind_IsSignalFrame (context))
     170      {
     171        /* The CFA is by definition unmodified in this case.  */
     172        fs->regs.cfa_how = CFA_REG_OFFSET;
     173        fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
     174        fs->regs.cfa_offset = 0;
     175  
     176        /* This is the canonical RA column.  */
     177        fs->retaddr_column = 15;
     178  
     179        return _URC_NO_REASON;
     180      }
     181  
     182    /* Do some pattern matching at the return address.  */
     183    if (IS_SIGHANDLER (pc, this_cfa, &nframes))
     184      {
     185        struct frame *fp = (struct frame *) this_cfa;
     186        struct handler_args {
     187  	struct frame frwin;
     188  	ucontext_t ucontext;
     189        } *handler_args;
     190        ucontext_t *ucp;
     191  
     192        /* this_cfa points into the frame after the saved frame pointer and
     193           saved pc (struct frame).
     194  
     195           The ucontext_t structure is in the kernel frame after a struct
     196           frame.  Since the frame sizes vary even within OS releases, we
     197           need to walk the stack to get there.  */
     198        for (i = 0; i < nframes; i++)
     199  	fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
     200  
     201        handler_args = (struct handler_args *) fp;
     202        ucp = &handler_args->ucontext;
     203        mctx = &ucp->uc_mcontext;
     204      }
     205    else
     206      return _URC_END_OF_STACK;
     207  
     208    /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
     209    new_cfa = mctx->gregs[REG_SP] + STACK_BIAS;
     210  
     211    fs->regs.cfa_how = CFA_REG_OFFSET;
     212    fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
     213    fs->regs.cfa_offset = new_cfa - (long) this_cfa + STACK_BIAS;
     214  
     215    /* Restore global and out registers (in this order) from the
     216       ucontext_t structure, uc_mcontext.gregs field.  */
     217    for (i = 1; i < 16; i++)
     218      {
     219        /* We never restore %sp as everything is purely CFA-based.  */
     220        if ((unsigned int) i == __builtin_dwarf_sp_column ())
     221  	continue;
     222  
     223        /* First the global registers and then the out registers.  */
     224        fs->regs.how[i] = REG_SAVED_OFFSET;
     225        fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
     226      }
     227  
     228    /* Just above the stack pointer there are 16 extended words in which
     229       the register window (in and local registers) was saved.  */
     230    for (i = 0; i < 16; i++)
     231      {
     232        fs->regs.how[i + 16] = REG_SAVED_OFFSET;
     233        fs->regs.reg[i + 16].loc.offset = i * sizeof(long);
     234      }
     235  
     236    /* Check whether we need to restore FPU registers.  */
     237    if (mctx->fpregs.fpu_qcnt)
     238      {
     239        for (i = 0; i < 32; i++)
     240  	{
     241  	  fs->regs.how[i + 32] = REG_SAVED_OFFSET;
     242  	  fs->regs.reg[i + 32].loc.offset
     243  	    = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
     244  	}
     245  
     246  #ifdef __arch64__
     247        /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles.  */
     248        for (i = 32; i < 64; i++)
     249  	{
     250  	  if (i > 32 && (i & 1))
     251  	    continue;
     252  
     253  	  fs->regs.how[i + 32] = REG_SAVED_OFFSET;
     254  	  fs->regs.reg[i + 32].loc.offset
     255  	    = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
     256  	}
     257  #endif
     258      }
     259  
     260    /* State the rules to find the kernel's code "return address", which is
     261       the address of the active instruction when the signal was caught.
     262       On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
     263       need to preventively subtract it from the purported return address.  */
     264    ra_location = &mctx->gregs[REG_PC];
     265    shifted_ra_location = &mctx->gregs[REG_Y];
     266    *(void **)shifted_ra_location = *(void **)ra_location - 8;
     267    fs->retaddr_column = 0;
     268    fs->regs.how[0] = REG_SAVED_OFFSET;
     269    fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
     270  
     271    /* SIGFPE for IEEE-754 exceptions is delivered after the faulting insn
     272       rather than before it, so don't set fs->signal_frame in that case.
     273       We test whether the cexc field of the FSR is zero.  */
     274    if ((mctx->fpregs.fpu_fsr & 0x1f) == 0)
     275      fs->signal_frame = 1;
     276  
     277    return _URC_NO_REASON;
     278  }