PR target/16201
[official-gcc.git] / gcc / config / ia64 / linux-unwind.h
blob801597ce3110d64b1b973c96bbe40faf11624e29
1 /* DWARF2 EH unwinding support for IA64 Linux.
2 Copyright (C) 2004 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 2, 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 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA. */
21 /* Do code reading to identify a signal frame, and set the frame
22 state data appropriately. See unwind-dw2.c for the structs. */
24 /* This works only for glibc-2.3 and later, because sigcontext is different
25 in glibc-2.2.4. */
27 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
28 #include <signal.h>
29 #include <sys/ucontext.h>
31 #define IA64_GATE_AREA_START 0xa000000000000100LL
32 #define IA64_GATE_AREA_END 0xa000000000030000LL
34 #define MD_FALLBACK_FRAME_STATE_FOR ia64_fallback_frame_state
36 static _Unwind_Reason_Code
37 ia64_fallback_frame_state (struct _Unwind_Context *context,
38 _Unwind_FrameState *fs)
40 if (context->rp >= IA64_GATE_AREA_START
41 && context->rp < IA64_GATE_AREA_END)
43 struct sigframe {
44 char scratch[16];
45 unsigned long sig_number;
46 struct siginfo *info;
47 struct sigcontext *sc;
48 } *frame_ = (struct sigframe *)context->psp;
49 struct sigcontext *sc = frame_->sc;
51 /* Restore scratch registers in case the unwinder needs to
52 refer to a value stored in one of them. */
54 int i;
56 for (i = 2; i < 4; i++)
57 context->ireg[i - 2].loc = &sc->sc_gr[i];
58 for (i = 8; i < 12; i++)
59 context->ireg[i - 2].loc = &sc->sc_gr[i];
60 for (i = 14; i < 32; i++)
61 context->ireg[i - 2].loc = &sc->sc_gr[i];
64 context->fpsr_loc = &(sc->sc_ar_fpsr);
65 context->pfs_loc = &(sc->sc_ar_pfs);
66 context->lc_loc = &(sc->sc_ar_lc);
67 context->unat_loc = &(sc->sc_ar_unat);
68 context->br_loc[0] = &(sc->sc_br[0]);
69 context->br_loc[6] = &(sc->sc_br[6]);
70 context->br_loc[7] = &(sc->sc_br[7]);
71 context->pr = sc->sc_pr;
72 context->psp = sc->sc_gr[12];
73 context->gp = sc->sc_gr[1];
74 /* Signal frame doesn't have an associated reg. stack frame
75 other than what we adjust for below. */
76 fs -> no_reg_stack_frame = 1;
78 if (sc->sc_rbs_base)
80 /* Need to switch from alternate register backing store. */
81 long ndirty, loadrs = sc->sc_loadrs >> 16;
82 unsigned long alt_bspstore = context->bsp - loadrs;
83 unsigned long bspstore;
84 unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
86 ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
87 (unsigned long *) context->bsp);
88 bspstore = (unsigned long)
89 ia64_rse_skip_regs (ar_bsp, -ndirty);
90 ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
91 sc->sc_ar_rnat);
94 /* Don't touch the branch registers o.t. b0, b6 and b7.
95 The kernel doesn't pass the preserved branch registers
96 in the sigcontext but leaves them intact, so there's no
97 need to do anything with them here. */
99 unsigned long sof = sc->sc_cfm & 0x7f;
100 context->bsp = (unsigned long)
101 ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
104 fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;
105 fs->curr.reg[UNW_REG_RP].val
106 = (unsigned long)&(sc->sc_ip) - context->psp;
107 fs->curr.reg[UNW_REG_RP].when = -1;
109 return _URC_NO_REASON;
111 return _URC_END_OF_STACK;
114 #define MD_HANDLE_UNWABI ia64_handle_unwabi
116 static void
117 ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
119 if (fs->unwabi == ((3 << 8) | 's')
120 || fs->unwabi == ((0 << 8) | 's'))
122 struct sigframe {
123 char scratch[16];
124 unsigned long sig_number;
125 struct siginfo *info;
126 struct sigcontext *sc;
127 } *frame = (struct sigframe *)context->psp;
128 struct sigcontext *sc = frame->sc;
130 /* Restore scratch registers in case the unwinder needs to
131 refer to a value stored in one of them. */
133 int i;
135 for (i = 2; i < 4; i++)
136 context->ireg[i - 2].loc = &sc->sc_gr[i];
137 for (i = 8; i < 12; i++)
138 context->ireg[i - 2].loc = &sc->sc_gr[i];
139 for (i = 14; i < 32; i++)
140 context->ireg[i - 2].loc = &sc->sc_gr[i];
143 context->pfs_loc = &(sc->sc_ar_pfs);
144 context->lc_loc = &(sc->sc_ar_lc);
145 context->unat_loc = &(sc->sc_ar_unat);
146 context->br_loc[0] = &(sc->sc_br[0]);
147 context->br_loc[6] = &(sc->sc_br[6]);
148 context->br_loc[7] = &(sc->sc_br[7]);
149 context->pr = sc->sc_pr;
150 context->gp = sc->sc_gr[1];
151 /* Signal frame doesn't have an associated reg. stack frame
152 other than what we adjust for below. */
153 fs -> no_reg_stack_frame = 1;
155 if (sc->sc_rbs_base)
157 /* Need to switch from alternate register backing store. */
158 long ndirty, loadrs = sc->sc_loadrs >> 16;
159 unsigned long alt_bspstore = context->bsp - loadrs;
160 unsigned long bspstore;
161 unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
163 ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
164 (unsigned long *) context->bsp);
165 bspstore = (unsigned long) ia64_rse_skip_regs (ar_bsp, -ndirty);
166 ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
167 sc->sc_ar_rnat);
170 /* Don't touch the branch registers o.t. b0, b6 and b7.
171 The kernel doesn't pass the preserved branch registers
172 in the sigcontext but leaves them intact, so there's no
173 need to do anything with them here. */
175 unsigned long sof = sc->sc_cfm & 0x7f;
176 context->bsp = (unsigned long)
177 ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
180 /* pfs_loc already set above. Without this pfs_loc would point
181 incorrectly to sc_cfm instead of sc_ar_pfs. */
182 fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;
185 #endif /* glibc-2.3 or better */