OSDN Git Service

PR target/18230
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / linux-unwind.h
1 /* DWARF2 EH unwinding support for SPARC Linux.
2    Copyright 2004 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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 2, or (at your option)
9 any later version.
10
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.
15
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
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Do code reading to identify a signal frame, and set the frame
22    state data appropriately.  See unwind-dw2.c for the structs.  */
23
24 /* Handle multilib correctly.  */
25 #if defined(__arch64__)
26
27 /* 64-bit SPARC version */
28 #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
29
30 static _Unwind_Reason_Code
31 sparc64_fallback_frame_state (struct _Unwind_Context *context,
32                               _Unwind_FrameState *fs)
33 {
34   unsigned int *pc = context->ra;
35   long new_cfa, i;
36   long regs_off, fpu_save_off;
37   long this_cfa, fpu_save;
38
39   if (pc[0] != 0x82102065               /* mov NR_rt_sigreturn, %g1 */
40       || pc[1] != 0x91d0206d)           /* ta 0x6d */
41     return _URC_END_OF_STACK;
42   regs_off = 192 + 128;
43   fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
44   this_cfa = (long) context->cfa;
45   new_cfa = *(long *)((context->cfa) + (regs_off + (14 * 8)));
46   new_cfa += 2047; /* Stack bias */
47   fpu_save = *(long *)((this_cfa) + (fpu_save_off));
48   fs->cfa_how = CFA_REG_OFFSET;
49   fs->cfa_reg = 14;
50   fs->cfa_offset = new_cfa - (long) context->cfa;
51   for (i = 1; i < 16; ++i)
52     {
53       fs->regs.reg[i].how = REG_SAVED_OFFSET;
54       fs->regs.reg[i].loc.offset =
55         this_cfa + (regs_off + (i * 8)) - new_cfa;
56     }
57   for (i = 0; i < 16; ++i)
58     {
59       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
60       fs->regs.reg[i + 16].loc.offset =
61         this_cfa + (i * 8) - new_cfa;
62     }
63   if (fpu_save)
64     {
65       for (i = 0; i < 64; ++i)
66         {
67           if (i > 32 && (i & 0x1))
68             continue;
69           fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
70           fs->regs.reg[i + 32].loc.offset =
71             (fpu_save + (i * 4)) - new_cfa;
72         }
73     }
74   /* Stick return address into %g0, same trick Alpha uses.  */
75   fs->regs.reg[0].how = REG_SAVED_OFFSET;
76   fs->regs.reg[0].loc.offset =
77     this_cfa + (regs_off + (16 * 8) + 8) - new_cfa;
78   fs->retaddr_column = 0;
79   return _URC_NO_REASON;
80 }
81
82 #else
83
84 /* 32-bit SPARC version */
85 #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
86
87 static _Unwind_Reason_Code
88 sparc_fallback_frame_state (struct _Unwind_Context *context,
89                             _Unwind_FrameState *fs)
90 {
91   unsigned int *pc = context->ra;
92   int new_cfa, i, oldstyle;
93   int regs_off, fpu_save_off;
94   int fpu_save, this_cfa;
95
96   if (pc[1] != 0x91d02010)              /* ta 0x10 */
97     return _URC_END_OF_STACK;
98   if (pc[0] == 0x821020d8)              /* mov NR_sigreturn, %g1 */
99     oldstyle = 1;
100   else if (pc[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */
101     oldstyle = 0;
102   else
103     return _URC_END_OF_STACK;
104   if (oldstyle)
105     {
106       regs_off = 96;
107       fpu_save_off = regs_off + (4 * 4) + (16 * 4);
108     }
109   else
110     {
111       regs_off = 96 + 128;
112       fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
113     }
114   this_cfa = (int) context->cfa;
115   new_cfa = *(int *)((context->cfa) + (regs_off+(4*4)+(14 * 4)));
116   fpu_save = *(int *)((this_cfa) + (fpu_save_off));
117   fs->cfa_how = CFA_REG_OFFSET;
118   fs->cfa_reg = 14;
119   fs->cfa_offset = new_cfa - (int) context->cfa;
120   for (i = 1; i < 16; ++i)
121     {
122       if (i == 14)
123         continue;
124       fs->regs.reg[i].how = REG_SAVED_OFFSET;
125       fs->regs.reg[i].loc.offset =
126         this_cfa + (regs_off+(4 * 4)+(i * 4)) - new_cfa;
127     }
128   for (i = 0; i < 16; ++i)
129     {
130       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
131       fs->regs.reg[i + 16].loc.offset =
132         this_cfa + (i * 4) - new_cfa;
133     }
134   if (fpu_save)
135     {
136       for (i = 0; i < 32; ++i)
137         {
138           fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
139           fs->regs.reg[i + 32].loc.offset =
140             (fpu_save + (i * 4)) - new_cfa;
141         }
142     }
143   /* Stick return address into %g0, same trick Alpha uses.  */
144   fs->regs.reg[0].how = REG_SAVED_OFFSET;
145   fs->regs.reg[0].loc.offset = this_cfa+(regs_off+4)-new_cfa;
146   fs->retaddr_column = 0;
147   return _URC_NO_REASON;
148 }
149
150 #endif