vms-unwind.h revision 1.1.1.11 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