(root)/
gcc-13.2.0/
libgcc/
config/
alpha/
vms-unwind.h
       1  /* Fallback frame unwinding for Alpha/VMS.
       2     Copyright (C) 1996-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 it
       7     under the terms of the GNU General Public License as published
       8     by the Free Software Foundation; either version 3, or (at your
       9     option) any later version.
      10  
      11     GCC is distributed in the hope that it will be useful, but WITHOUT
      12     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      13     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      14     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  #include <stdlib.h>
      26  #include <stdio.h>
      27  #include <vms/pdscdef.h>
      28  #include <vms/libicb.h>
      29  #include <vms/chfctxdef.h>
      30  #include <vms/chfdef.h>
      31  
      32  #define MD_FALLBACK_FRAME_STATE_FOR alpha_vms_fallback_frame_state
      33  
      34  typedef void * ADDR;
      35  typedef unsigned long long REG;
      36  typedef PDSCDEF * PV;
      37  
      38  #define REG_AT(addr) (*(REG *)(addr))
      39  #define ADDR_AT(addr) (*(ADDR *)(addr))
      40  
      41  /* Compute pointer to procedure descriptor (Procedure Value) from Frame
      42     Pointer FP, according to the rules in [ABI-3.5.1 Current Procedure].  */
      43  #define PV_FOR(FP) \
      44    (((FP) != 0) \
      45      ? (((REG_AT (FP) & 0x7) == 0) ? *(PDSCDEF **)(FP) : (PDSCDEF *)(FP)) : 0)
      46  
      47  extern int SYS$GL_CALL_HANDL;
      48  /* This is actually defined as a "long", but in system code where longs
      49     are always 4bytes while GCC longs might be 8bytes.  */
      50  
      51  #define UPDATE_FS_FOR_CFA_GR(FS, GRN, LOC, CFA) \
      52  do { \
      53  (FS)->regs.how[GRN] = REG_SAVED_OFFSET;      \
      54  (FS)->regs.reg[GRN].loc.offset = (_Unwind_Sword) ((REG) (LOC) - (REG) (CFA)); \
      55  } while (0);
      56  
      57  #define GIVEUP_ON_FAILURE(STATUS) \
      58    { if ((((STATUS) & 1) != 1)) return _URC_END_OF_STACK; }
      59  #define DENOTES_EXC_DISPATCHER(PV) ((PV) == (ADDR) (REG) SYS$GL_CALL_HANDL)
      60  
      61  #define RA_COLUMN (__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__)
      62  
      63  static int
      64  alpha_vms_fallback_frame_state (struct _Unwind_Context *context,
      65  				_Unwind_FrameState *fs)
      66  {
      67    static int eh_debug = -1;
      68  
      69    /* Our goal is to update FS to reflect the state one step up CONTEXT, that
      70       is: the CFA, return address and *saved* registers locations associated
      71       with the function designated by CONTEXT->ra.  We are called when the
      72       libgcc unwinder has not found any dwarf FDE for this address, which
      73       typically happens when trying to propagate a language exception through a
      74       signal global vector or frame based handler.
      75  
      76       The CONTEXT->reg[] entries reflect the state/location of register saves
      77       so designate values live at the CONTEXT->ra point.  Of precious value to
      78       us here is the frame pointer (r29), which gets us a procedure value.  */
      79  
      80    PV pv = (context->reg[29] != 0) ? PV_FOR (ADDR_AT (context->reg[29])) : 0;
      81  
      82    int pkind = pv ? pv->pdsc$w_flags & 0xf : 0;
      83    /* VMS procedure kind, as indicated by the procedure descriptor.  We only
      84       know how to deal with FP_STACK or FP_REGISTER here.  */
      85  
      86    ADDR new_cfa = 0;
      87    /* CFA we will establish for the caller, computed in different ways,
      88       e.g. depending whether we cross an exception dispatcher frame.  */
      89  
      90    CHFCTX *chfctx = 0;
      91    /* Pointer to the VMS CHF context associated with an exception dispatcher
      92       frame, if we happen to come across one.  */
      93  
      94    int i,j;
      95  
      96    if (eh_debug == -1)
      97      {
      98        char * eh_debug_env = getenv ("EH_DEBUG");
      99        eh_debug = eh_debug_env ? atoi (eh_debug_env) : 0;
     100      }
     101  
     102    if (eh_debug)
     103      printf ("MD_FALLBACK running ...\n");
     104  
     105    /* We only know how to deal with stack or reg frame procedures, so give
     106       up if we're handed anything else.  */
     107    if (pkind != PDSC$K_KIND_FP_STACK && pkind != PDSC$K_KIND_FP_REGISTER)
     108      return _URC_END_OF_STACK;
     109    
     110    if (eh_debug)
     111      printf ("FALLBACK: CTX FP = 0x%p, PV = 0x%p, EN = 0x%llx, RA = 0x%p\n",
     112  	    ADDR_AT (context->reg[29]), pv, pv->pdsc$q_entry, context->ra);
     113  
     114    fs->retaddr_column = RA_COLUMN;
     115  
     116    /* If PV designates a VMS exception vector or condition handler, we need to
     117       do as if the caller was the signaling point and estabish the state of the
     118       intermediate VMS code (CFA, RA and saved register locations) as if it was
     119       a single regular function.  This requires special processing.
     120  
     121       The datastructures available from an condition dispatcher frame (signal
     122       context) do not contain the values of most callee-saved registers, so
     123       whathever PV designates, we need to account for the registers it saves.
     124  
     125       Besides, we need to express all the locations with respect to a
     126       consistent CFA value, so we compute this first.  */
     127  
     128    if (DENOTES_EXC_DISPATCHER (pv))
     129      {
     130        /* The CFA to establish is the signaling point's stack pointer. We
     131  	 compute it using the system invocation context unwinding services and
     132  	 save the CHF context data pointer along the way for later uses.  */
     133  
     134        INVO_CONTEXT_BLK icb;
     135        int status, invo_handle;
     136  
     137        if (eh_debug)
     138  	printf ("FALLBACK: SYS$HANDLER\n");
     139  
     140        icb.libicb$q_ireg [29] = REG_AT (context->reg[29]);
     141        icb.libicb$q_ireg [30] = 0;
     142        invo_handle = LIB$GET_INVO_HANDLE (&icb);
     143  
     144        status = LIB$GET_INVO_CONTEXT (invo_handle, &icb);
     145        GIVEUP_ON_FAILURE (status);
     146  
     147        chfctx = (CHFCTX *) icb.libicb$ph_chfctx_addr;
     148  
     149        status = LIB$GET_PREV_INVO_CONTEXT (&icb);
     150        GIVEUP_ON_FAILURE (status);
     151  
     152        new_cfa = (ADDR) icb.libicb$q_ireg[30];      
     153      }
     154    else
     155      {
     156        /* The CFA to establish is the SP value on entry of the procedure
     157  	 designated by PV, which we compute as the corresponding frame base
     158  	 register value + frame size.  Note that the frame base may differ
     159  	 from CONTEXT->cfa, typically if the caller has performed dynamic
     160  	 stack allocations.  */
     161        
     162        int  base_reg  = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30;
     163        ADDR base_addr = ADDR_AT (context->reg[base_reg]);
     164        
     165        new_cfa = base_addr + pv->pdsc$l_size;
     166      }
     167  
     168    /* State to compute the caller's CFA by adding an offset to the current
     169       one in CONTEXT.  */
     170    fs->regs.cfa_how = CFA_REG_OFFSET;
     171    fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
     172    fs->regs.cfa_offset = new_cfa - context->cfa;
     173  
     174    /* Regular unwind first, accounting for the register saves performed by
     175       the procedure designated by PV.  */
     176  
     177    switch (pkind)
     178      {
     179      case PDSC$K_KIND_FP_STACK:
     180        {
     181  	/* The saved registers are all located in the Register Save Area,
     182  	   except for the procedure value register (R27) found at the frame
     183  	   base address.  */
     184  
     185  	int  base_reg  = pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP ? 29 : 30;
     186  	ADDR base_addr = ADDR_AT (context->reg[base_reg]);
     187  	ADDR rsa_addr  = base_addr + pv->pdsc$w_rsa_offset;
     188  
     189  	if (eh_debug)
     190  	  printf ("FALLBACK: STACK frame procedure\n");
     191  
     192  	UPDATE_FS_FOR_CFA_GR (fs, 27, base_addr, new_cfa);
     193  
     194  	/* The first RSA entry is for the return address register, R26.  */
     195  
     196  	UPDATE_FS_FOR_CFA_GR (fs, 26, rsa_addr, new_cfa);
     197  	UPDATE_FS_FOR_CFA_GR (fs, RA_COLUMN, rsa_addr, new_cfa);
     198  
     199  	/* The following entries are for registers marked as saved according
     200  	   to ireg_mask.  */
     201  	for (i = 0, j = 0; i < 32; i++)
     202  	  if ((1 << i) & pv->pdsc$l_ireg_mask)
     203  	    UPDATE_FS_FOR_CFA_GR (fs, i, rsa_addr + 8 * ++j, new_cfa);
     204  	
     205  	/* ??? floating point registers ?  */
     206  
     207  	break;
     208        }
     209  
     210      case PDSC$K_KIND_FP_REGISTER:
     211        {
     212  	if (eh_debug)
     213  	  printf ("FALLBACK: REGISTER frame procedure\n");
     214  
     215  	fs->regs.how[RA_COLUMN] = REG_SAVED_REG;
     216  	fs->regs.reg[RA_COLUMN].loc.reg = pv->pdsc$b_save_ra;
     217  	
     218  	fs->regs.how[29] = REG_SAVED_REG;
     219  	fs->regs.reg[29].loc.reg = pv->pdsc$b_save_fp;
     220  	
     221  	break;
     222        }
     223  
     224      default:
     225        /* Should never reach here.  */
     226        return _URC_END_OF_STACK;
     227      }
     228  
     229    /* If PV designates an exception dispatcher, we have to adjust the return
     230       address column to get at the signal occurrence point, and account for
     231       what the CHF context contains.  */
     232  
     233    if (DENOTES_EXC_DISPATCHER (pv))
     234      {
     235        /* The PC of the instruction causing the condition is available from the
     236  	 signal argument vector.  Extra saved register values are available
     237  	 from the mechargs array.  */
     238  
     239        CHF$SIGNAL_ARRAY *sigargs
     240  	= (CHF$SIGNAL_ARRAY *) chfctx->chfctx$q_sigarglst;
     241  
     242        CHF$MECH_ARRAY *mechargs
     243  	= (CHF$MECH_ARRAY *) chfctx->chfctx$q_mcharglst;
     244  
     245        ADDR condpc_addr
     246  	= &((int *)(&sigargs->chf$l_sig_name)) [sigargs->chf$is_sig_args-2];
     247  
     248        ADDR rei_frame_addr = (void *) mechargs->chf$q_mch_esf_addr;
     249  
     250        /* Adjust the return address location.  */
     251  
     252        UPDATE_FS_FOR_CFA_GR (fs, RA_COLUMN, condpc_addr, new_cfa);
     253  
     254        /* The frame pointer at the condition point is available from the
     255  	 chf context directly.  */
     256  
     257        UPDATE_FS_FOR_CFA_GR (fs, 29, &chfctx->chfctx$q_expt_fp, new_cfa);
     258  
     259        /* Registers available from the mechargs array.  */
     260  
     261        UPDATE_FS_FOR_CFA_GR (fs, 0, &mechargs->chf$q_mch_savr0, new_cfa);
     262        UPDATE_FS_FOR_CFA_GR (fs, 1, &mechargs->chf$q_mch_savr1, new_cfa);
     263  
     264        UPDATE_FS_FOR_CFA_GR (fs, 16, &mechargs->chf$q_mch_savr16, new_cfa);
     265        UPDATE_FS_FOR_CFA_GR (fs, 17, &mechargs->chf$q_mch_savr17, new_cfa);
     266        UPDATE_FS_FOR_CFA_GR (fs, 18, &mechargs->chf$q_mch_savr18, new_cfa);
     267        UPDATE_FS_FOR_CFA_GR (fs, 19, &mechargs->chf$q_mch_savr19, new_cfa);
     268        UPDATE_FS_FOR_CFA_GR (fs, 20, &mechargs->chf$q_mch_savr20, new_cfa);
     269        UPDATE_FS_FOR_CFA_GR (fs, 21, &mechargs->chf$q_mch_savr21, new_cfa);
     270        UPDATE_FS_FOR_CFA_GR (fs, 22, &mechargs->chf$q_mch_savr22, new_cfa);
     271        UPDATE_FS_FOR_CFA_GR (fs, 23, &mechargs->chf$q_mch_savr23, new_cfa);
     272        UPDATE_FS_FOR_CFA_GR (fs, 24, &mechargs->chf$q_mch_savr24, new_cfa);
     273        UPDATE_FS_FOR_CFA_GR (fs, 25, &mechargs->chf$q_mch_savr25, new_cfa);
     274        UPDATE_FS_FOR_CFA_GR (fs, 26, &mechargs->chf$q_mch_savr26, new_cfa);
     275        UPDATE_FS_FOR_CFA_GR (fs, 27, &mechargs->chf$q_mch_savr27, new_cfa);
     276        UPDATE_FS_FOR_CFA_GR (fs, 28, &mechargs->chf$q_mch_savr28, new_cfa);
     277        
     278        /* Registers R2 to R7 are available from the rei frame pointer.  */
     279        
     280        for (i = 2; i <= 7; i ++)
     281  	UPDATE_FS_FOR_CFA_GR (fs, i, rei_frame_addr+(i - 2)*8, new_cfa);
     282        
     283        /* ??? floating point registers ?  */
     284      }
     285  
     286    fs->signal_frame = 1;
     287  
     288    return _URC_NO_REASON;
     289  }
     290  
     291  
     292