1 /* DWARF2 EH unwinding support for SPARC Linux.
2 Copyright 2004, 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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public 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 /* Do code reading to identify a signal frame, and set the frame
26 state data appropriately. See unwind-dw2.c for the structs. */
28 #if defined(__arch64__)
30 /* 64-bit SPARC version */
31 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
33 static _Unwind_Reason_Code
34 sparc64_fallback_frame_state (struct _Unwind_Context *context,
35 _Unwind_FrameState *fs)
37 unsigned int *pc = context->ra;
38 long this_cfa = (long) context->cfa;
39 long new_cfa, ra_location, shifted_ra_location;
40 long regs_off, fpu_save_off;
44 if (pc[0] != 0x82102065 /* mov NR_rt_sigreturn, %g1 */
45 || pc[1] != 0x91d0206d) /* ta 0x6d */
46 return _URC_END_OF_STACK;
49 fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
51 new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
52 new_cfa += 2047; /* Stack bias */
53 fpu_save = *(long *)(this_cfa + fpu_save_off);
54 fs->regs.cfa_how = CFA_REG_OFFSET;
55 fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
56 fs->regs.cfa_offset = new_cfa - this_cfa;
58 for (i = 1; i < 16; i++)
60 /* We never restore %sp as everything is purely CFA-based. */
61 if ((unsigned int) i == __builtin_dwarf_sp_column ())
64 fs->regs.reg[i].how = REG_SAVED_OFFSET;
65 fs->regs.reg[i].loc.offset
66 = this_cfa + regs_off + (i * 8) - new_cfa;
68 for (i = 0; i < 16; i++)
70 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
71 fs->regs.reg[i + 16].loc.offset
72 = this_cfa + (i * 8) - new_cfa;
76 for (i = 0; i < 64; i++)
78 if (i > 32 && (i & 0x1))
80 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
81 fs->regs.reg[i + 32].loc.offset
82 = fpu_save + (i * 4) - new_cfa;
86 /* State the rules to find the kernel's code "return address", which is
87 the address of the active instruction when the signal was caught.
88 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
89 need to preventively subtract it from the purported return address. */
90 ra_location = this_cfa + regs_off + 17 * 8;
91 shifted_ra_location = this_cfa + regs_off + 19 * 8; /* Y register */
92 *(long *)shifted_ra_location = *(long *)ra_location - 8;
93 fs->retaddr_column = 0;
94 fs->regs.reg[0].how = REG_SAVED_OFFSET;
95 fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
98 return _URC_NO_REASON;
101 #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
104 sparc64_frob_update_context (struct _Unwind_Context *context,
105 _Unwind_FrameState *fs)
107 /* The column of %sp contains the old CFA, not the old value of %sp.
108 The CFA offset already comprises the stack bias so, when %sp is the
109 CFA register, we must avoid counting the stack bias twice. Do not
110 do that for signal frames as the offset is artificial for them. */
111 if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
112 && fs->regs.cfa_how == CFA_REG_OFFSET
113 && fs->regs.cfa_offset != 0
114 && !fs->signal_frame)
115 context->cfa -= 2047;
120 /* 32-bit SPARC version */
121 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
123 static _Unwind_Reason_Code
124 sparc_fallback_frame_state (struct _Unwind_Context *context,
125 _Unwind_FrameState *fs)
127 unsigned int *pc = context->ra;
128 int this_cfa = (int) context->cfa;
129 int new_cfa, ra_location, shifted_ra_location;
130 int regs_off, fpu_save_off;
134 if (pc[1] != 0x91d02010) /* ta 0x10 */
135 return _URC_END_OF_STACK;
137 if (pc[0] == 0x821020d8) /* mov NR_sigreturn, %g1 */
139 else if (pc[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */
142 return _URC_END_OF_STACK;
147 fpu_save_off = regs_off + (4 * 4) + (16 * 4);
152 fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
155 new_cfa = *(int *)(this_cfa + regs_off + (4 * 4) + (14 * 4));
156 fpu_save = *(int *)(this_cfa + fpu_save_off);
157 fs->regs.cfa_how = CFA_REG_OFFSET;
158 fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
159 fs->regs.cfa_offset = new_cfa - this_cfa;
161 for (i = 1; i < 16; i++)
163 /* We never restore %sp as everything is purely CFA-based. */
164 if ((unsigned int) i == __builtin_dwarf_sp_column ())
167 fs->regs.reg[i].how = REG_SAVED_OFFSET;
168 fs->regs.reg[i].loc.offset
169 = this_cfa + regs_off + (4 * 4) + (i * 4) - new_cfa;
171 for (i = 0; i < 16; i++)
173 fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
174 fs->regs.reg[i + 16].loc.offset
175 = this_cfa + (i * 4) - new_cfa;
179 for (i = 0; i < 32; i++)
181 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
182 fs->regs.reg[i + 32].loc.offset
183 = fpu_save + (i * 4) - new_cfa;
187 /* State the rules to find the kernel's code "return address", which is
188 the address of the active instruction when the signal was caught.
189 On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
190 need to preventively subtract it from the purported return address. */
191 ra_location = this_cfa + regs_off + 4;
192 shifted_ra_location = this_cfa + regs_off + 3 * 4; /* Y register */
193 *(int *)shifted_ra_location = *(int *)ra_location - 8;
194 fs->retaddr_column = 0;
195 fs->regs.reg[0].how = REG_SAVED_OFFSET;
196 fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
197 fs->signal_frame = 1;
199 return _URC_NO_REASON;