linux-unwind.h revision 256281
1227569Sphilip/* DWARF2 EH unwinding support for IA64 Linux.
2284555Sarybchik   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3284555Sarybchik
4227569Sphilip   This file is part of GCC.
5227569Sphilip
6284555Sarybchik   GCC is free software; you can redistribute it and/or modify it
7227569Sphilip   under the terms of the GNU General Public License as published
8284555Sarybchik   by the Free Software Foundation; either version 2, or (at your
9284555Sarybchik   option) any later version.
10284555Sarybchik
11284555Sarybchik   In addition to the permissions in the GNU General Public License,
12284555Sarybchik   the Free Software Foundation gives you unlimited permission to link
13228078Sphilip   the compiled version of this file with other programs, and to
14284555Sarybchik   distribute those programs without any restriction coming from the
15284555Sarybchik   use of this file.  (The General Public License restrictions do
16284555Sarybchik   apply in other respects; for example, they cover modification of
17284555Sarybchik   the file, and distribution when not linked into another program.)
18284555Sarybchik
19284555Sarybchik   GCC is distributed in the hope that it will be useful, but WITHOUT
20284555Sarybchik   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21284555Sarybchik   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22284555Sarybchik   License for more details.
23284555Sarybchik
24284555Sarybchik   You should have received a copy of the GNU General Public License
25284555Sarybchik   along with GCC; see the file COPYING.  If not, write to the
26284555Sarybchik   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
27284555Sarybchik   MA 02110-1301, USA.  */
28284555Sarybchik
29284555Sarybchik/* Do code reading to identify a signal frame, and set the frame
30228078Sphilip   state data appropriately.  See unwind-dw2.c for the structs.  */
31227569Sphilip
32227569Sphilip/* This works only for glibc-2.3 and later, because sigcontext is different
33227569Sphilip   in glibc-2.2.4.  */
34227569Sphilip
35227569Sphilip#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
36227569Sphilip#include <signal.h>
37227569Sphilip#include <sys/ucontext.h>
38227569Sphilip
39227569Sphilip#define IA64_GATE_AREA_START 0xa000000000000100LL
40227569Sphilip#define IA64_GATE_AREA_END   0xa000000000030000LL
41227569Sphilip
42227569Sphilip#define MD_FALLBACK_FRAME_STATE_FOR ia64_fallback_frame_state
43227569Sphilip
44227569Sphilipstatic _Unwind_Reason_Code
45227569Sphilipia64_fallback_frame_state (struct _Unwind_Context *context,
46227569Sphilip			   _Unwind_FrameState *fs)
47227569Sphilip{
48227569Sphilip  if (context->rp >= IA64_GATE_AREA_START
49227569Sphilip      && context->rp < IA64_GATE_AREA_END)
50227569Sphilip    {
51227569Sphilip      struct sigframe {
52227569Sphilip	char scratch[16];
53227569Sphilip	unsigned long sig_number;
54227569Sphilip	struct siginfo *info;
55227569Sphilip	struct sigcontext *sc;
56227569Sphilip      } *frame_ = (struct sigframe *)context->psp;
57227569Sphilip      struct sigcontext *sc = frame_->sc;
58293927Sarybchik
59227569Sphilip      /* Restore scratch registers in case the unwinder needs to
60227569Sphilip	 refer to a value stored in one of them.  */
61227569Sphilip      {
62227569Sphilip	int i;
63227569Sphilip
64293927Sarybchik	for (i = 2; i < 4; i++)
65227569Sphilip	  context->ireg[i - 2].loc = &sc->sc_gr[i];
66227569Sphilip	for (i = 8; i < 12; i++)
67227569Sphilip	  context->ireg[i - 2].loc = &sc->sc_gr[i];
68227569Sphilip	for (i = 14; i < 32; i++)
69227569Sphilip	  context->ireg[i - 2].loc = &sc->sc_gr[i];
70293927Sarybchik      }
71227569Sphilip
72227569Sphilip      context->fpsr_loc = &(sc->sc_ar_fpsr);
73227569Sphilip      context->pfs_loc = &(sc->sc_ar_pfs);
74293927Sarybchik      context->lc_loc = &(sc->sc_ar_lc);
75227569Sphilip      context->unat_loc = &(sc->sc_ar_unat);
76227569Sphilip      context->br_loc[0] = &(sc->sc_br[0]);
77227569Sphilip      context->br_loc[6] = &(sc->sc_br[6]);
78227569Sphilip      context->br_loc[7] = &(sc->sc_br[7]);
79227569Sphilip      context->pr = sc->sc_pr;
80293927Sarybchik      context->psp = sc->sc_gr[12];
81227569Sphilip      context->gp = sc->sc_gr[1];
82227569Sphilip      /* Signal frame doesn't have an associated reg. stack frame
83227569Sphilip         other than what we adjust for below.	  */
84227569Sphilip      fs -> no_reg_stack_frame = 1;
85227569Sphilip
86227569Sphilip      if (sc->sc_rbs_base)
87227569Sphilip	{
88227569Sphilip	  /* Need to switch from alternate register backing store.  */
89227569Sphilip	  long ndirty, loadrs = sc->sc_loadrs >> 16;
90227569Sphilip	  unsigned long alt_bspstore = context->bsp - loadrs;
91227569Sphilip	  unsigned long bspstore;
92227569Sphilip	  unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
93227569Sphilip
94227569Sphilip	  ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
95227569Sphilip				      (unsigned long *) context->bsp);
96227569Sphilip	  bspstore = (unsigned long)
97227569Sphilip	    ia64_rse_skip_regs (ar_bsp, -ndirty);
98227569Sphilip	  ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
99227569Sphilip			 sc->sc_ar_rnat);
100227569Sphilip	}
101227569Sphilip
102293927Sarybchik      /* Don't touch the branch registers o.t. b0, b6 and b7.
103227569Sphilip	 The kernel doesn't pass the preserved branch registers
104227569Sphilip	 in the sigcontext but leaves them intact, so there's no
105227569Sphilip	 need to do anything with them here.  */
106227569Sphilip      {
107227569Sphilip	unsigned long sof = sc->sc_cfm & 0x7f;
108227569Sphilip	context->bsp = (unsigned long)
109284555Sarybchik	  ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
110227569Sphilip      }
111293927Sarybchik
112284555Sarybchik      fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;
113284555Sarybchik      fs->curr.reg[UNW_REG_RP].val
114284555Sarybchik	= (unsigned long)&(sc->sc_ip) - context->psp;
115284555Sarybchik      fs->curr.reg[UNW_REG_RP].when = -1;
116284555Sarybchik
117294378Sarybchik      return _URC_NO_REASON;
118284555Sarybchik    }
119294378Sarybchik  return _URC_END_OF_STACK;
120294378Sarybchik}
121294378Sarybchik
122294378Sarybchik#define MD_HANDLE_UNWABI ia64_handle_unwabi
123284555Sarybchik
124293972Sarybchikstatic void
125293972Sarybchikia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
126293972Sarybchik{
127293972Sarybchik  if (fs->unwabi == ((3 << 8) | 's')
128293960Sarybchik      || fs->unwabi == ((0 << 8) | 's'))
129293960Sarybchik    {
130294017Sarybchik      struct sigframe {
131294017Sarybchik	char scratch[16];
132294017Sarybchik	unsigned long sig_number;
133294017Sarybchik	struct siginfo *info;
134293960Sarybchik	struct sigcontext *sc;
135293927Sarybchik      } *frame = (struct sigframe *)context->psp;
136284555Sarybchik      struct sigcontext *sc = frame->sc;
137284555Sarybchik
138284555Sarybchik      /* Restore scratch registers in case the unwinder needs to
139284555Sarybchik	 refer to a value stored in one of them.  */
140284555Sarybchik      {
141284555Sarybchik	int i;
142284555Sarybchik
143293927Sarybchik	for (i = 2; i < 4; i++)
144293969Sarybchik	  context->ireg[i - 2].loc = &sc->sc_gr[i];
145284555Sarybchik	for (i = 8; i < 12; i++)
146293969Sarybchik	  context->ireg[i - 2].loc = &sc->sc_gr[i];
147284555Sarybchik	for (i = 14; i < 32; i++)
148284555Sarybchik	  context->ireg[i - 2].loc = &sc->sc_gr[i];
149284555Sarybchik      }
150284555Sarybchik
151227569Sphilip      context->pfs_loc = &(sc->sc_ar_pfs);
152227569Sphilip      context->lc_loc = &(sc->sc_ar_lc);
153293927Sarybchik      context->unat_loc = &(sc->sc_ar_unat);
154227569Sphilip      context->br_loc[0] = &(sc->sc_br[0]);
155227569Sphilip      context->br_loc[6] = &(sc->sc_br[6]);
156294002Sarybchik      context->br_loc[7] = &(sc->sc_br[7]);
157227569Sphilip      context->pr = sc->sc_pr;
158227569Sphilip      context->gp = sc->sc_gr[1];
159227569Sphilip      /* Signal frame doesn't have an associated reg. stack frame
160227569Sphilip         other than what we adjust for below.	  */
161294002Sarybchik      fs -> no_reg_stack_frame = 1;
162227569Sphilip
163293927Sarybchik      if (sc->sc_rbs_base)
164227569Sphilip	{
165227569Sphilip	  /* Need to switch from alternate register backing store.  */
166294002Sarybchik	  long ndirty, loadrs = sc->sc_loadrs >> 16;
167227569Sphilip	  unsigned long alt_bspstore = context->bsp - loadrs;
168227569Sphilip	  unsigned long bspstore;
169227569Sphilip	  unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
170227569Sphilip
171227569Sphilip	  ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
172227569Sphilip				      (unsigned long *) context->bsp);
173227569Sphilip	  bspstore = (unsigned long) ia64_rse_skip_regs (ar_bsp, -ndirty);
174227569Sphilip	  ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
175227569Sphilip			 sc->sc_ar_rnat);
176227569Sphilip	}
177293927Sarybchik
178227569Sphilip      /* Don't touch the branch registers o.t. b0, b6 and b7.
179227569Sphilip	 The kernel doesn't pass the preserved branch registers
180227569Sphilip	 in the sigcontext but leaves them intact, so there's no
181227569Sphilip	 need to do anything with them here.  */
182227569Sphilip      {
183293927Sarybchik	unsigned long sof = sc->sc_cfm & 0x7f;
184284555Sarybchik	context->bsp = (unsigned long)
185284555Sarybchik	  ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
186294002Sarybchik      }
187284555Sarybchik
188284555Sarybchik      /* pfs_loc already set above.  Without this pfs_loc would point
189293927Sarybchik	 incorrectly to sc_cfm instead of sc_ar_pfs.  */
190294379Sarybchik      fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_NONE;
191227569Sphilip    }
192227569Sphilip}
193294379Sarybchik#endif /* glibc-2.3 or better */
194227569Sphilip