1 /* DWARF2 EH unwinding support for IA64 VMS.
2 Copyright (C) 2005-2009 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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.
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/>. */
25 #include <vms/libicb.h>
26 #include <vms/chfdef.h>
27 #include <vms/chfctxdef.h>
29 #define __int64 long long
30 #include <vms/intstkdef.h>
35 #define DYN$C_SSENTRY 66
36 /* ??? would rather get the proper header file. */
38 #define MD_FALLBACK_FRAME_STATE_FOR ia64_vms_fallback_frame_state
40 extern INVO_CONTEXT_BLK * LIB$I64_CREATE_INVO_CONTEXT (void);
42 extern int LIB$I64_IS_EXC_DISPATCH_FRAME (void *);
43 extern int LIB$I64_IS_AST_DISPATCH_FRAME (void *);
45 extern int LIB$I64_INIT_INVO_CONTEXT (INVO_CONTEXT_BLK *, int, int);
46 extern int LIB$I64_GET_CURR_INVO_CONTEXT (INVO_CONTEXT_BLK *);
47 extern int LIB$I64_GET_PREV_INVO_CONTEXT (INVO_CONTEXT_BLK *);
49 typedef unsigned long ulong;
50 typedef unsigned int uint;
51 typedef unsigned long uw_reg;
52 typedef uw_reg * uw_loc;
54 typedef char fp_reg[16];
56 #define DENOTES_VMS_DISPATCHER_FRAME(icb) \
57 (LIB$I64_IS_EXC_DISPATCH_FRAME (&(icb)->libicb$ih_pc))
59 #define DENOTES_BOTTOM_OF_STACK(icb) ((icb)->libicb$v_bottom_of_stack)
61 #define FAIL_IF(COND) \
62 do { if (COND) { context->rp = 0; return _URC_END_OF_STACK; } } while (0)
63 /* Clearing context->rp is required to prevent the ia64 gcc unwinder from
64 attempting to keep on walking the call chain. */
67 ia64_vms_fallback_frame_state (struct _Unwind_Context *context,
68 _Unwind_FrameState *fs)
72 INVO_CONTEXT_BLK local_icb;
73 INVO_CONTEXT_BLK *icb = &local_icb;
76 CHF$MECH_ARRAY * chfmech;
77 CHF64$SIGNAL_ARRAY *chfsig64;
80 static int eh_debug = -1;
82 /* Non zero to attempt copy of alternate backing store contents for
83 dirty partition in interrupted context. ??? Alpha code, only activated
84 on specific request via specific bit in EH_DEBUG. */
88 char * EH_DEBUG = getenv ("EH_DEBUG");
89 const uint try_bs_copy_mask = (1 << 16);
91 eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0;
93 /* Fetch and clear the try_bs_copy bit. */
94 try_bs_copy = (uint)eh_debug & try_bs_copy_mask;
95 eh_debug &= ~try_bs_copy_mask;
98 /* We're called to attempt unwinding through a frame for which no unwind
99 info is available, typical of an operating system exception dispatcher
100 frame. The code below knows how to handle this case, and only this one,
101 returning a failure code if it finds it is not in this situation.
103 Note that we're called from deep down in the exception propagation call
104 chain, possibly below an exception dispatcher but for a frame above it
105 like some os entry point. */
108 printf ("FALLBACK - ctxt->rp=0x%lx, sp=0x%lx, psp=0x%lx, bsp=0x%lx\n",
109 context->rp, context->sp, context->psp, context->bsp);
112 -------------------------------------------------------------------------
113 VMS-unwind up until we reach a VMS dispatcher frame corresponding to the
114 context we are trying to unwind through. Fail if get past this context or
115 if we reach the bottom of stack along the way.
116 -------------------------------------------------------------------------
119 status = LIB$I64_INIT_INVO_CONTEXT (icb, LIBICB$K_INVO_CONTEXT_VERSION, 0);
120 FAIL_IF (status == 0);
122 status = LIB$I64_GET_CURR_INVO_CONTEXT (icb);
124 /* Beware: we might be unwinding through nested condition handlers, so the
125 dispatcher frame we seek might not be the first one on the way up. Loop
129 /* Seek the next dispatcher frame up the "current" point. Stop if we
130 either get past the target context or hit the bottom-of-stack along
132 status = LIB$I64_GET_PREV_INVO_CONTEXT (icb);
133 FAIL_IF (status == 0);
134 FAIL_IF ((uw_reg)icb->libicb$ih_sp > (uw_reg)context->psp
135 || DENOTES_BOTTOM_OF_STACK (icb));
138 printf ("frame%s sp @ 0x%llx, pc @ 0x%llx bsp=0x%llx\n",
139 DENOTES_VMS_DISPATCHER_FRAME (icb) ? " (dispatcher)" : "",
140 icb->libicb$ih_sp, icb->libicb$ih_pc, icb->libicb$ih_bsp);
142 /* Continue until the target frame is found. */
143 } while ((uw_reg)icb->libicb$ih_bsp != (uw_reg)context->bsp);
145 /* If this is not a dispatcher frame, this is certainly a frame for a leaf
146 subprogram. Use default unwind information. */
147 if (! DENOTES_VMS_DISPATCHER_FRAME (icb))
148 return _URC_END_OF_STACK;
150 /* At this point, we know we are really trying to unwind past an exception
151 dispatcher frame, and have it described in ICB. Proceed. */
154 ------------------------------------------------------------------------
155 We have the VMS dispatcher frame ICB handy and know we are trying to
156 unwind past it. Fetch pointers to useful datastructures from there, then
157 unwind one step further up to the interrupted user context from which
158 some required values will be easily accessible.
159 ------------------------------------------------------------------------
162 chfctx = icb->libicb$ph_chfctx_addr;
163 FAIL_IF (chfctx == 0);
165 chfmech = (CHF$MECH_ARRAY *)chfctx->chfctx$q_mcharglst;
166 FAIL_IF (chfmech == 0);
168 chfsig64 = (CHF64$SIGNAL_ARRAY *)chfmech->chf$ph_mch_sig64_addr;
169 FAIL_IF (chfsig64 == 0);
171 intstk = (INTSTK *)chfmech->chf$q_mch_esf_addr;
172 FAIL_IF (intstk == 0 || intstk->intstk$b_subtype == DYN$C_SSENTRY);
174 status = LIB$I64_GET_PREV_INVO_CONTEXT (icb);
175 FAIL_IF (status == 0);
178 printf ("User frame, "
179 "chfmech @ 0x%lx, chfsig64 @ 0x%lx, intstk @ 0x%lx\n",
180 (ulong)chfmech, (ulong)chfsig64, (ulong)intstk);
183 ------------------------------------------------------------------------
184 Point the GCC context locations/values required for further unwinding at
185 their corresponding locations/values in the datastructures at hand.
186 ------------------------------------------------------------------------
189 /* Static General Register locations, including scratch registers in case
190 the unwinder needs to refer to a value stored in one of them. */
192 uw_reg * ctxregs = (uw_reg *)&intstk->intstk$q_regbase;
194 for (i = 2; i <= 3; i++)
195 context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
196 for (i = 8; i <= 11; i++)
197 context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
198 for (i = 14; i <= 31; i++)
199 context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
202 /* Static Floating Point Register locations, as available from the
203 mechargs array, which happens to include all the to be preserved
208 ctxregs = (fp_reg *)&chfmech->chf$fh_mch_savf2;
209 for (i = 2; i <= 5 ; i++)
210 context->fr_loc[i - 2] = (uw_loc)&ctxregs[i - 2];
212 ctxregs = (fp_reg *)&chfmech->chf$fh_mch_savf12;
213 for (i = 12; i <= 31 ; i++)
214 context->fr_loc[i - 2] = (uw_loc)&ctxregs[i - 12];
217 /* Relevant application register locations. */
219 context->fpsr_loc = (uw_loc)&intstk->intstk$q_fpsr;
220 context->lc_loc = (uw_loc)&intstk->intstk$q_lc;
221 context->unat_loc = (uw_loc)&intstk->intstk$q_unat;
223 /* Branch register locations. */
226 uw_reg * ctxregs = (uw_reg *)&intstk->intstk$q_b0;
228 for (i = 0; i < 8; i++)
229 context->br_loc[i] = (uw_loc)&ctxregs[i];
232 /* Necessary register values. */
234 /* ??? Still unclear if we need to account for possible flushes to an
235 alternate backing store (maybe the unwinding performed above did the
236 trick already) and how this would be handled. Blind alpha tentative
237 below for experimentation purposes in malfunctioning cases. */
239 ulong q_bsp = (ulong) intstk->intstk$q_bsp;
240 ulong q_bspstore = (ulong) intstk->intstk$q_bspstore;
241 ulong q_bspbase = (ulong) intstk->intstk$q_bspbase;
242 ulong ih_bspbase = (ulong) icb->libicb$ih_bspbase;
245 printf ("q_bspstore = 0x%lx, q_bsp = 0x%lx, q_bspbase = 0x%lx\n"
246 "ih_bspbase = 0x%lx\n",
247 q_bspstore, q_bsp, q_bspbase, ih_bspbase);
249 /* We witness many situations where q_bspbase is set while ih_bspbase is
250 null, and every attempt made with q_bspbase badly failed while doing
251 nothing resulted in proper behavior. */
252 if (q_bspstore < q_bsp && ih_bspbase && try_bs_copy)
254 ulong dirty_size = q_bsp - q_bspstore;
255 ulong q_rnat = (ulong) intstk->intstk$q_rnat;
258 printf ("Attempting an alternate backing store copy ...\n");
261 (context, q_bspstore, ih_bspbase, dirty_size, q_rnat);
262 /* Not clear if these are the proper arguments here. This is what
263 looked the closest to what is performed in the Linux case. */
268 context->bsp = (uw_reg)intstk->intstk$q_bsp;
269 fs->no_reg_stack_frame = 1;
271 context->pr = (uw_reg)intstk->intstk$q_preds;
272 context->gp = (uw_reg)intstk->intstk$q_gp;
274 /* We're directly setting up the "context" for a VMS exception handler.
275 The "previous SP" for it is the SP upon the handler's entry, that is
276 the SP at the condition/interruption/exception point. */
277 context->psp = (uw_reg)icb->libicb$ih_sp;
279 /* Previous Frame State location. What eventually ends up in pfs_loc is
280 installed with ar.pfs = pfs_loc; br.ret; so setup to target intstk->q_ifs
281 to have the interrupted context restored and not that of its caller if
282 we happen to have a handler in the interrupted context itself. */
283 fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_PSPREL;
284 fs->curr.reg[UNW_REG_PFS].val
285 = (uw_reg)&intstk->intstk$q_ifs - (uw_reg)context->psp;
286 fs->curr.reg[UNW_REG_PFS].when = -1;
288 /* If we need to unwind further up, past the interrupted context, we need to
289 hand out the interrupted context's pfs, still. */
290 context->signal_pfs_loc = (uw_loc) &intstk->intstk$q_pfs;
292 /* Finally, rules for RP . */
294 uw_reg * post_sigarray
295 = (uw_reg *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;
297 uw_reg * ih_pc_loc = post_sigarray - 2;
299 fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_PSPREL;
300 fs->curr.reg[UNW_REG_RP].val
301 = (uw_reg)ih_pc_loc - (uw_reg)context->psp;
302 fs->curr.reg[UNW_REG_RP].when = -1;
305 return _URC_NO_REASON;