1169689Skan/* DWARF2 EH unwinding support for IA64 Linux.
2169689Skan   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3169689Skan
4169689Skan   This file is part of GCC.
5169689Skan
6169689Skan   GCC is free software; you can redistribute it and/or modify it
7169689Skan   under the terms of the GNU General Public License as published
8169689Skan   by the Free Software Foundation; either version 2, or (at your
9169689Skan   option) any later version.
10169689Skan
11169689Skan   In addition to the permissions in the GNU General Public License,
12169689Skan   the Free Software Foundation gives you unlimited permission to link
13169689Skan   the compiled version of this file with other programs, and to
14169689Skan   distribute those programs without any restriction coming from the
15169689Skan   use of this file.  (The General Public License restrictions do
16169689Skan   apply in other respects; for example, they cover modification of
17169689Skan   the file, and distribution when not linked into another program.)
18169689Skan
19169689Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
20169689Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21169689Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22169689Skan   License for more details.
23169689Skan
24169689Skan   You should have received a copy of the GNU General Public License
25169689Skan   along with GCC; see the file COPYING.  If not, write to the
26169689Skan   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
27169689Skan   MA 02110-1301, USA.  */
28169689Skan
29169689Skan/* Do code reading to identify a signal frame, and set the frame
30169689Skan   state data appropriately.  See unwind-dw2.c for the structs.  */
31169689Skan
32169689Skan/* This works only for glibc-2.3 and later, because sigcontext is different
33169689Skan   in glibc-2.2.4.  */
34169689Skan
35169689Skan#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
36169689Skan#include <signal.h>
37169689Skan#include <sys/ucontext.h>
38169689Skan
39169689Skan#define IA64_GATE_AREA_START 0xa000000000000100LL
40169689Skan#define IA64_GATE_AREA_END   0xa000000000030000LL
41169689Skan
42169689Skan#define MD_FALLBACK_FRAME_STATE_FOR ia64_fallback_frame_state
43169689Skan
44169689Skanstatic _Unwind_Reason_Code
45169689Skania64_fallback_frame_state (struct _Unwind_Context *context,
46169689Skan			   _Unwind_FrameState *fs)
47169689Skan{
48169689Skan  if (context->rp >= IA64_GATE_AREA_START
49169689Skan      && context->rp < IA64_GATE_AREA_END)
50169689Skan    {
51169689Skan      struct sigframe {
52169689Skan	char scratch[16];
53169689Skan	unsigned long sig_number;
54169689Skan	struct siginfo *info;
55169689Skan	struct sigcontext *sc;
56169689Skan      } *frame_ = (struct sigframe *)context->psp;
57169689Skan      struct sigcontext *sc = frame_->sc;
58169689Skan
59169689Skan      /* Restore scratch registers in case the unwinder needs to
60169689Skan	 refer to a value stored in one of them.  */
61169689Skan      {
62169689Skan	int i;
63169689Skan
64169689Skan	for (i = 2; i < 4; i++)
65169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
66169689Skan	for (i = 8; i < 12; i++)
67169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
68169689Skan	for (i = 14; i < 32; i++)
69169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
70169689Skan      }
71169689Skan
72169689Skan      context->fpsr_loc = &(sc->sc_ar_fpsr);
73169689Skan      context->pfs_loc = &(sc->sc_ar_pfs);
74169689Skan      context->lc_loc = &(sc->sc_ar_lc);
75169689Skan      context->unat_loc = &(sc->sc_ar_unat);
76169689Skan      context->br_loc[0] = &(sc->sc_br[0]);
77169689Skan      context->br_loc[6] = &(sc->sc_br[6]);
78169689Skan      context->br_loc[7] = &(sc->sc_br[7]);
79169689Skan      context->pr = sc->sc_pr;
80169689Skan      context->psp = sc->sc_gr[12];
81169689Skan      context->gp = sc->sc_gr[1];
82169689Skan      /* Signal frame doesn't have an associated reg. stack frame
83169689Skan         other than what we adjust for below.	  */
84169689Skan      fs -> no_reg_stack_frame = 1;
85169689Skan
86169689Skan      if (sc->sc_rbs_base)
87169689Skan	{
88169689Skan	  /* Need to switch from alternate register backing store.  */
89169689Skan	  long ndirty, loadrs = sc->sc_loadrs >> 16;
90169689Skan	  unsigned long alt_bspstore = context->bsp - loadrs;
91169689Skan	  unsigned long bspstore;
92169689Skan	  unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
93169689Skan
94169689Skan	  ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
95169689Skan				      (unsigned long *) context->bsp);
96169689Skan	  bspstore = (unsigned long)
97169689Skan	    ia64_rse_skip_regs (ar_bsp, -ndirty);
98169689Skan	  ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
99169689Skan			 sc->sc_ar_rnat);
100169689Skan	}
101169689Skan
102169689Skan      /* Don't touch the branch registers o.t. b0, b6 and b7.
103169689Skan	 The kernel doesn't pass the preserved branch registers
104169689Skan	 in the sigcontext but leaves them intact, so there's no
105169689Skan	 need to do anything with them here.  */
106169689Skan      {
107169689Skan	unsigned long sof = sc->sc_cfm & 0x7f;
108169689Skan	context->bsp = (unsigned long)
109169689Skan	  ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
110169689Skan      }
111169689Skan
112169689Skan      fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;
113169689Skan      fs->curr.reg[UNW_REG_RP].val
114169689Skan	= (unsigned long)&(sc->sc_ip) - context->psp;
115169689Skan      fs->curr.reg[UNW_REG_RP].when = -1;
116169689Skan
117169689Skan      return _URC_NO_REASON;
118169689Skan    }
119169689Skan  return _URC_END_OF_STACK;
120169689Skan}
121169689Skan
122169689Skan#define MD_HANDLE_UNWABI ia64_handle_unwabi
123169689Skan
124169689Skanstatic void
125169689Skania64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
126169689Skan{
127169689Skan  if (fs->unwabi == ((3 << 8) | 's')
128169689Skan      || fs->unwabi == ((0 << 8) | 's'))
129169689Skan    {
130169689Skan      struct sigframe {
131169689Skan	char scratch[16];
132169689Skan	unsigned long sig_number;
133169689Skan	struct siginfo *info;
134169689Skan	struct sigcontext *sc;
135169689Skan      } *frame = (struct sigframe *)context->psp;
136169689Skan      struct sigcontext *sc = frame->sc;
137169689Skan
138169689Skan      /* Restore scratch registers in case the unwinder needs to
139169689Skan	 refer to a value stored in one of them.  */
140169689Skan      {
141169689Skan	int i;
142169689Skan
143169689Skan	for (i = 2; i < 4; i++)
144169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
145169689Skan	for (i = 8; i < 12; i++)
146169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
147169689Skan	for (i = 14; i < 32; i++)
148169689Skan	  context->ireg[i - 2].loc = &sc->sc_gr[i];
149169689Skan      }
150169689Skan
151169689Skan      context->pfs_loc = &(sc->sc_ar_pfs);
152169689Skan      context->lc_loc = &(sc->sc_ar_lc);
153169689Skan      context->unat_loc = &(sc->sc_ar_unat);
154169689Skan      context->br_loc[0] = &(sc->sc_br[0]);
155169689Skan      context->br_loc[6] = &(sc->sc_br[6]);
156169689Skan      context->br_loc[7] = &(sc->sc_br[7]);
157169689Skan      context->pr = sc->sc_pr;
158169689Skan      context->gp = sc->sc_gr[1];
159169689Skan      /* Signal frame doesn't have an associated reg. stack frame
160169689Skan         other than what we adjust for below.	  */
161169689Skan      fs -> no_reg_stack_frame = 1;
162169689Skan
163169689Skan      if (sc->sc_rbs_base)
164169689Skan	{
165169689Skan	  /* Need to switch from alternate register backing store.  */
166169689Skan	  long ndirty, loadrs = sc->sc_loadrs >> 16;
167169689Skan	  unsigned long alt_bspstore = context->bsp - loadrs;
168169689Skan	  unsigned long bspstore;
169169689Skan	  unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
170169689Skan
171169689Skan	  ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
172169689Skan				      (unsigned long *) context->bsp);
173169689Skan	  bspstore = (unsigned long) ia64_rse_skip_regs (ar_bsp, -ndirty);
174169689Skan	  ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
175169689Skan			 sc->sc_ar_rnat);
176169689Skan	}
177169689Skan
178169689Skan      /* Don't touch the branch registers o.t. b0, b6 and b7.
179169689Skan	 The kernel doesn't pass the preserved branch registers
180169689Skan	 in the sigcontext but leaves them intact, so there's no
181169689Skan	 need to do anything with them here.  */
182169689Skan      {
183169689Skan	unsigned long sof = sc->sc_cfm & 0x7f;
184169689Skan	context->bsp = (unsigned long)
185169689Skan	  ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
186169689Skan      }
187169689Skan
188169689Skan      /* pfs_loc already set above.  Without this pfs_loc would point
189169689Skan	 incorrectly to sc_cfm instead of sc_ar_pfs.  */
190169689Skan      fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;
191169689Skan    }
192169689Skan}
193169689Skan#endif /* glibc-2.3 or better */
194