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