1169689Skan/* DWARF2 EH unwinding support for SPARC Linux.
2169689Skan   Copyright 2004, 2005 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify
7169689Skanit under the terms of the GNU General Public License as published by
8169689Skanthe Free Software Foundation; either version 2, or (at your option)
9169689Skanany later version.
10169689Skan
11169689SkanIn addition to the permissions in the GNU General Public License, the
12169689SkanFree Software Foundation gives you unlimited permission to link the
13169689Skancompiled version of this file with other programs, and to distribute
14169689Skanthose programs without any restriction coming from the use of this
15169689Skanfile.  (The General Public License restrictions do apply in other
16169689Skanrespects; for example, they cover modification of the file, and
17169689Skandistribution when not linked into another program.)
18169689Skan
19169689SkanGCC is distributed in the hope that it will be useful,
20169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
21169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22169689SkanGNU General Public License for more details.
23169689Skan
24169689SkanYou should have received a copy of the GNU General Public License
25169689Skanalong with GCC; see the file COPYING.  If not, write to
26169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
27169689SkanBoston, 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/* Handle multilib correctly.  */
33169689Skan#if defined(__arch64__)
34169689Skan
35169689Skan/* 64-bit SPARC version */
36169689Skan#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
37169689Skan
38169689Skanstatic _Unwind_Reason_Code
39169689Skansparc64_fallback_frame_state (struct _Unwind_Context *context,
40169689Skan			      _Unwind_FrameState *fs)
41169689Skan{
42169689Skan  unsigned int *pc = context->ra;
43169689Skan  long new_cfa, i;
44169689Skan  long regs_off, fpu_save_off;
45169689Skan  long this_cfa, fpu_save;
46169689Skan
47169689Skan  if (pc[0] != 0x82102065		/* mov NR_rt_sigreturn, %g1 */
48169689Skan      || pc[1] != 0x91d0206d)		/* ta 0x6d */
49169689Skan    return _URC_END_OF_STACK;
50169689Skan  regs_off = 192 + 128;
51169689Skan  fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
52169689Skan  this_cfa = (long) context->cfa;
53169689Skan  new_cfa = *(long *)((context->cfa) + (regs_off + (14 * 8)));
54169689Skan  new_cfa += 2047; /* Stack bias */
55169689Skan  fpu_save = *(long *)((this_cfa) + (fpu_save_off));
56169689Skan  fs->cfa_how = CFA_REG_OFFSET;
57169689Skan  fs->cfa_reg = 14;
58169689Skan  fs->cfa_offset = new_cfa - (long) context->cfa;
59169689Skan  for (i = 1; i < 16; ++i)
60169689Skan    {
61169689Skan      fs->regs.reg[i].how = REG_SAVED_OFFSET;
62169689Skan      fs->regs.reg[i].loc.offset =
63169689Skan	this_cfa + (regs_off + (i * 8)) - new_cfa;
64169689Skan    }
65169689Skan  for (i = 0; i < 16; ++i)
66169689Skan    {
67169689Skan      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
68169689Skan      fs->regs.reg[i + 16].loc.offset =
69169689Skan	this_cfa + (i * 8) - new_cfa;
70169689Skan    }
71169689Skan  if (fpu_save)
72169689Skan    {
73169689Skan      for (i = 0; i < 64; ++i)
74169689Skan	{
75169689Skan	  if (i > 32 && (i & 0x1))
76169689Skan	    continue;
77169689Skan	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
78169689Skan	  fs->regs.reg[i + 32].loc.offset =
79169689Skan	    (fpu_save + (i * 4)) - new_cfa;
80169689Skan	}
81169689Skan    }
82169689Skan  /* Stick return address into %g0, same trick Alpha uses.  */
83169689Skan  fs->regs.reg[0].how = REG_SAVED_OFFSET;
84169689Skan  fs->regs.reg[0].loc.offset =
85169689Skan    this_cfa + (regs_off + (16 * 8) + 8) - new_cfa;
86169689Skan  fs->retaddr_column = 0;
87169689Skan  return _URC_NO_REASON;
88169689Skan}
89169689Skan
90169689Skan#else
91169689Skan
92169689Skan/* 32-bit SPARC version */
93169689Skan#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
94169689Skan
95169689Skanstatic _Unwind_Reason_Code
96169689Skansparc_fallback_frame_state (struct _Unwind_Context *context,
97169689Skan			    _Unwind_FrameState *fs)
98169689Skan{
99169689Skan  unsigned int *pc = context->ra;
100169689Skan  int new_cfa, i, oldstyle;
101169689Skan  int regs_off, fpu_save_off;
102169689Skan  int fpu_save, this_cfa;
103169689Skan
104169689Skan  if (pc[1] != 0x91d02010)		/* ta 0x10 */
105169689Skan    return _URC_END_OF_STACK;
106169689Skan  if (pc[0] == 0x821020d8)		/* mov NR_sigreturn, %g1 */
107169689Skan    oldstyle = 1;
108169689Skan  else if (pc[0] == 0x82102065)	/* mov NR_rt_sigreturn, %g1 */
109169689Skan    oldstyle = 0;
110169689Skan  else
111169689Skan    return _URC_END_OF_STACK;
112169689Skan  if (oldstyle)
113169689Skan    {
114169689Skan      regs_off = 96;
115169689Skan      fpu_save_off = regs_off + (4 * 4) + (16 * 4);
116169689Skan    }
117169689Skan  else
118169689Skan    {
119169689Skan      regs_off = 96 + 128;
120169689Skan      fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
121169689Skan    }
122169689Skan  this_cfa = (int) context->cfa;
123169689Skan  new_cfa = *(int *)((context->cfa) + (regs_off+(4*4)+(14 * 4)));
124169689Skan  fpu_save = *(int *)((this_cfa) + (fpu_save_off));
125169689Skan  fs->cfa_how = CFA_REG_OFFSET;
126169689Skan  fs->cfa_reg = 14;
127169689Skan  fs->cfa_offset = new_cfa - (int) context->cfa;
128169689Skan  for (i = 1; i < 16; ++i)
129169689Skan    {
130169689Skan      if (i == 14)
131169689Skan	continue;
132169689Skan      fs->regs.reg[i].how = REG_SAVED_OFFSET;
133169689Skan      fs->regs.reg[i].loc.offset =
134169689Skan	this_cfa + (regs_off+(4 * 4)+(i * 4)) - new_cfa;
135169689Skan    }
136169689Skan  for (i = 0; i < 16; ++i)
137169689Skan    {
138169689Skan      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
139169689Skan      fs->regs.reg[i + 16].loc.offset =
140169689Skan	this_cfa + (i * 4) - new_cfa;
141169689Skan    }
142169689Skan  if (fpu_save)
143169689Skan    {
144169689Skan      for (i = 0; i < 32; ++i)
145169689Skan	{
146169689Skan	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
147169689Skan	  fs->regs.reg[i + 32].loc.offset =
148169689Skan	    (fpu_save + (i * 4)) - new_cfa;
149169689Skan	}
150169689Skan    }
151169689Skan  /* Stick return address into %g0, same trick Alpha uses.  */
152169689Skan  fs->regs.reg[0].how = REG_SAVED_OFFSET;
153169689Skan  fs->regs.reg[0].loc.offset = this_cfa+(regs_off+4)-new_cfa;
154169689Skan  fs->retaddr_column = 0;
155169689Skan  return _URC_NO_REASON;
156169689Skan}
157169689Skan
158169689Skan#endif
159