1/* DWARF2 EH unwinding support for PA HP-UX.
2   Copyright (C) 2005 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11In addition to the permissions in the GNU General Public License, the
12Free Software Foundation gives you unlimited permission to link the
13compiled version of this file with other programs, and to distribute
14those programs without any restriction coming from the use of this
15file.  (The General Public License restrictions do apply in other
16respects; for example, they cover modification of the file, and
17distribution when not linked into another program.)
18
19GCC is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License
25along with GCC; see the file COPYING.  If not, write to
26the Free Software Foundation, 51 Franklin Street, Fifth Floor,
27Boston, MA 02110-1301, USA.  */
28
29/* Do code reading to identify a signal frame, and set the frame
30   state data appropriately.  See unwind-dw2.c for the structs.  */
31
32#include <signal.h>
33#include <sys/ucontext.h>
34#include <unistd.h>
35
36/* FIXME: We currently ignore the high halves of general, space and
37   control registers on PA 2.0 machines for applications using the
38   32-bit runtime.  We don't restore space registers or the floating
39   point status registers.  */
40
41#define MD_FALLBACK_FRAME_STATE_FOR pa_fallback_frame_state
42
43/* HP-UX 10.X doesn't define GetSSReg.  */
44#ifndef GetSSReg
45#define GetSSReg(ssp, ss_reg) \
46  ((UseWideRegs (ssp))							\
47   ? (ssp)->ss_wide.ss_32.ss_reg ## _lo					\
48   : (ssp)->ss_narrow.ss_reg)
49#endif
50
51#if TARGET_64BIT
52#define GetSSRegAddr(ssp, ss_reg) ((long) &((ssp)->ss_wide.ss_64.ss_reg))
53#else
54#define GetSSRegAddr(ssp, ss_reg) \
55  ((UseWideRegs (ssp))							\
56   ? (long) &((ssp)->ss_wide.ss_32.ss_reg ## _lo)			\
57   : (long) &((ssp)->ss_narrow.ss_reg))
58#endif
59
60#define UPDATE_FS_FOR_SAR(FS, N) \
61  (FS)->regs.reg[N].how = REG_SAVED_OFFSET;				\
62  (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_cr11) - new_cfa
63
64#define UPDATE_FS_FOR_GR(FS, GRN, N) \
65  (FS)->regs.reg[N].how = REG_SAVED_OFFSET;				\
66  (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_gr##GRN) - new_cfa
67
68#define UPDATE_FS_FOR_FR(FS, FRN, N) \
69  (FS)->regs.reg[N].how = REG_SAVED_OFFSET;				\
70  (FS)->regs.reg[N].loc.offset = (long) &(mc->ss_fr##FRN) - new_cfa;
71
72#define UPDATE_FS_FOR_PC(FS, N) \
73  (FS)->regs.reg[N].how = REG_SAVED_OFFSET;				\
74  (FS)->regs.reg[N].loc.offset = GetSSRegAddr (mc, ss_pcoq_head) - new_cfa
75
76/* Extract bit field from word using HP's numbering (MSB = 0).  */
77#define GET_FIELD(X, FROM, TO) \
78  ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
79
80static inline int
81sign_extend (int x, int len)
82{
83  int signbit = (1 << (len - 1));
84  int mask = (signbit << 1) - 1;
85  return ((x & mask) ^ signbit) - signbit;
86}
87
88/* Extract a 17-bit signed constant from branch instructions.  */
89static inline int
90extract_17 (unsigned word)
91{
92  return sign_extend (GET_FIELD (word, 19, 28)
93		      | GET_FIELD (word, 29, 29) << 10
94		      | GET_FIELD (word, 11, 15) << 11
95		      | (word & 0x1) << 16, 17);
96}
97
98/* Extract a 22-bit signed constant from branch instructions.  */
99static inline int
100extract_22 (unsigned word)
101{
102  return sign_extend (GET_FIELD (word, 19, 28)
103		      | GET_FIELD (word, 29, 29) << 10
104		      | GET_FIELD (word, 11, 15) << 11
105		      | GET_FIELD (word, 6, 10) << 16
106		      | (word & 0x1) << 21, 22);
107}
108
109static _Unwind_Reason_Code
110pa_fallback_frame_state (struct _Unwind_Context *context,
111			 _Unwind_FrameState *fs)
112{
113  static long cpu;
114  unsigned int *pc = (unsigned int *) context->ra;
115
116  if (pc == 0)
117    return _URC_END_OF_STACK;
118
119  /* Check if the return address points to an export stub (PA 1.1 or 2.0).  */
120  if ((!TARGET_64BIT
121       && *(pc + 0) == 0x4bc23fd1		/* ldw -18(sp),rp */
122       && *(pc + 1) == 0x004010a1		/* ldsid (rp),r1 */
123       && *(pc + 2) == 0x00011820		/* mtsp r1,sr0 */
124       && *(pc + 3) == 0xe0400002)		/* be,n 0(sr0,rp) */
125      ||
126      (!TARGET_64BIT
127       && *(pc + 0) == 0x4bc23fd1		/* ldw -18(sp),rp */
128       && *(pc + 1) == 0xe840d002))		/* bve,n (rp) */
129    {
130      fs->cfa_how    = CFA_REG_OFFSET;
131      fs->cfa_reg    = 30;
132      fs->cfa_offset = 0;
133
134      fs->retaddr_column = 0;
135      fs->regs.reg[0].how = REG_SAVED_OFFSET;
136      fs->regs.reg[0].loc.offset = -24;
137
138      return _URC_NO_REASON;
139    }
140
141  /* Check if the return address is an export stub as signal handlers
142     may return via an export stub.  */
143  if (!TARGET_64BIT
144      && (*pc & 0xffe0e002) == 0xe8400000	/* bl x,r2 */
145      && *(pc + 1) == 0x08000240		/* nop */
146      && *(pc + 2) == 0x4bc23fd1		/* ldw -18(sp),rp */
147      && *(pc + 3) == 0x004010a1		/* ldsid (rp),r1 */
148      && *(pc + 4) == 0x00011820		/* mtsp r1,sr0 */
149      && *(pc + 5) == 0xe0400002)		/* be,n 0(sr0,rp) */
150    /* Extract target address from PA 1.x 17-bit branch.  */
151    pc += extract_17 (*pc) + 2;
152  else if (!TARGET_64BIT
153	   && (*pc & 0xfc00e002) == 0xe800a000	/* b,l x,r2 */
154	   && *(pc + 1) == 0x08000240		/* nop */
155	   && *(pc + 2) == 0x4bc23fd1		/* ldw -18(sp),rp */
156	   && *(pc + 3) == 0xe840d002)		/* bve,n (rp) */
157    /* Extract target address from PA 2.0 22-bit branch.  */
158    pc += extract_22 (*pc) + 2;
159
160  /* Now check if the return address is one of the signal handler
161     returns, _sigreturn or _sigsetreturn.  */
162  if ((TARGET_64BIT
163       && *(pc + 0)  == 0x53db3f51		/* ldd -58(sp),dp */
164       && *(pc + 8)  == 0x34160116		/* ldi 8b,r22 */
165       && *(pc + 9)  == 0x08360ac1		/* shladd,l r22,3,r1,r1 */
166       && *(pc + 10) == 0x0c2010c1		/* ldd 0(r1),r1 */
167       && *(pc + 11) == 0xe4202000)		/* be,l 0(sr4,r1) */
168      ||
169      (TARGET_64BIT
170       && *(pc + 0)  == 0x36dc0000		/* ldo 0(r22),ret0 */
171       && *(pc + 6)  == 0x341601c0		/* ldi e0,r22 */
172       && *(pc + 7)  == 0x08360ac1		/* shladd,l r22,3,r1,r1 */
173       && *(pc + 8)  == 0x0c2010c1		/* ldd 0(r1),r1 */
174       && *(pc + 9)  == 0xe4202000)		/* be,l 0(sr4,r1) */
175      ||
176      (!TARGET_64BIT
177       && *(pc + 0)  == 0x379a0000		/* ldo 0(ret0),r26 */
178       && *(pc + 1)  == 0x6bd33fc9		/* stw r19,-1c(sp) */
179       && *(pc + 2)  == 0x20200801		/* ldil L%-40000000,r1 */
180       && *(pc + 3)  == 0xe420e008		/* be,l 4(sr7,r1) */
181       && *(pc + 4)  == 0x34160116)		/* ldi 8b,r22 */
182      ||
183      (!TARGET_64BIT
184       && *(pc + 0)  == 0x6bd33fc9		/* stw r19,-1c(sp) */
185       && *(pc + 1)  == 0x20200801		/* ldil L%-40000000,r1 */
186       && *(pc + 2)  == 0xe420e008		/* be,l 4(sr7,r1) */
187       && *(pc + 3)  == 0x341601c0))		/* ldi e0,r22 */
188    {
189      /* The previous stack pointer is saved at (long *)SP - 1.  The
190	 ucontext structure is offset from the start of the previous
191	 frame by the siglocal_misc structure.  */
192      struct siglocalx *sl = (struct siglocalx *)
193	(*((long *) context->cfa - 1));
194      mcontext_t *mc = &(sl->sl_uc.uc_mcontext);
195
196      long new_cfa = GetSSReg (mc, ss_sp);
197
198      fs->cfa_how = CFA_REG_OFFSET;
199      fs->cfa_reg = 30;
200      fs->cfa_offset = new_cfa - (long) context->cfa;
201
202      UPDATE_FS_FOR_GR (fs, 1, 1);
203      UPDATE_FS_FOR_GR (fs, 2, 2);
204      UPDATE_FS_FOR_GR (fs, 3, 3);
205      UPDATE_FS_FOR_GR (fs, 4, 4);
206      UPDATE_FS_FOR_GR (fs, 5, 5);
207      UPDATE_FS_FOR_GR (fs, 6, 6);
208      UPDATE_FS_FOR_GR (fs, 7, 7);
209      UPDATE_FS_FOR_GR (fs, 8, 8);
210      UPDATE_FS_FOR_GR (fs, 9, 9);
211      UPDATE_FS_FOR_GR (fs, 10, 10);
212      UPDATE_FS_FOR_GR (fs, 11, 11);
213      UPDATE_FS_FOR_GR (fs, 12, 12);
214      UPDATE_FS_FOR_GR (fs, 13, 13);
215      UPDATE_FS_FOR_GR (fs, 14, 14);
216      UPDATE_FS_FOR_GR (fs, 15, 15);
217      UPDATE_FS_FOR_GR (fs, 16, 16);
218      UPDATE_FS_FOR_GR (fs, 17, 17);
219      UPDATE_FS_FOR_GR (fs, 18, 18);
220      UPDATE_FS_FOR_GR (fs, 19, 19);
221      UPDATE_FS_FOR_GR (fs, 20, 20);
222      UPDATE_FS_FOR_GR (fs, 21, 21);
223      UPDATE_FS_FOR_GR (fs, 22, 22);
224      UPDATE_FS_FOR_GR (fs, 23, 23);
225      UPDATE_FS_FOR_GR (fs, 24, 24);
226      UPDATE_FS_FOR_GR (fs, 25, 25);
227      UPDATE_FS_FOR_GR (fs, 26, 26);
228      UPDATE_FS_FOR_GR (fs, 27, 27);
229      UPDATE_FS_FOR_GR (fs, 28, 28);
230      UPDATE_FS_FOR_GR (fs, 29, 29);
231      UPDATE_FS_FOR_GR (fs, 30, 30);
232      UPDATE_FS_FOR_GR (fs, 31, 31);
233
234      if (TARGET_64BIT)
235	{
236	  UPDATE_FS_FOR_FR (fs, 4, 32);
237	  UPDATE_FS_FOR_FR (fs, 5, 33);
238	  UPDATE_FS_FOR_FR (fs, 6, 34);
239	  UPDATE_FS_FOR_FR (fs, 7, 35);
240	  UPDATE_FS_FOR_FR (fs, 8, 36);
241	  UPDATE_FS_FOR_FR (fs, 9, 37);
242	  UPDATE_FS_FOR_FR (fs, 10, 38);
243	  UPDATE_FS_FOR_FR (fs, 11, 39);
244	  UPDATE_FS_FOR_FR (fs, 12, 40);
245	  UPDATE_FS_FOR_FR (fs, 13, 41);
246	  UPDATE_FS_FOR_FR (fs, 14, 42);
247	  UPDATE_FS_FOR_FR (fs, 15, 43);
248	  UPDATE_FS_FOR_FR (fs, 16, 44);
249	  UPDATE_FS_FOR_FR (fs, 17, 45);
250	  UPDATE_FS_FOR_FR (fs, 18, 46);
251	  UPDATE_FS_FOR_FR (fs, 19, 47);
252	  UPDATE_FS_FOR_FR (fs, 20, 48);
253	  UPDATE_FS_FOR_FR (fs, 21, 49);
254	  UPDATE_FS_FOR_FR (fs, 22, 50);
255	  UPDATE_FS_FOR_FR (fs, 23, 51);
256	  UPDATE_FS_FOR_FR (fs, 24, 52);
257	  UPDATE_FS_FOR_FR (fs, 25, 53);
258	  UPDATE_FS_FOR_FR (fs, 26, 54);
259	  UPDATE_FS_FOR_FR (fs, 27, 55);
260	  UPDATE_FS_FOR_FR (fs, 28, 56);
261	  UPDATE_FS_FOR_FR (fs, 29, 57);
262	  UPDATE_FS_FOR_FR (fs, 30, 58);
263	  UPDATE_FS_FOR_FR (fs, 31, 59);
264
265	  UPDATE_FS_FOR_SAR (fs, 60);
266	}
267      else
268	{
269	  UPDATE_FS_FOR_FR (fs, 4, 32);
270	  UPDATE_FS_FOR_FR (fs, 5, 34);
271	  UPDATE_FS_FOR_FR (fs, 6, 36);
272	  UPDATE_FS_FOR_FR (fs, 7, 38);
273	  UPDATE_FS_FOR_FR (fs, 8, 40);
274	  UPDATE_FS_FOR_FR (fs, 9, 44);
275	  UPDATE_FS_FOR_FR (fs, 10, 44);
276	  UPDATE_FS_FOR_FR (fs, 11, 46);
277	  UPDATE_FS_FOR_FR (fs, 12, 48);
278	  UPDATE_FS_FOR_FR (fs, 13, 50);
279	  UPDATE_FS_FOR_FR (fs, 14, 52);
280	  UPDATE_FS_FOR_FR (fs, 15, 54);
281
282	  if (!cpu)
283	    cpu = sysconf (_SC_CPU_VERSION);
284
285	  /* PA-RISC 1.0 only has 16 floating point registers.  */
286	  if (cpu != CPU_PA_RISC1_0)
287	    {
288	      UPDATE_FS_FOR_FR (fs, 16, 56);
289	      UPDATE_FS_FOR_FR (fs, 17, 58);
290	      UPDATE_FS_FOR_FR (fs, 18, 60);
291	      UPDATE_FS_FOR_FR (fs, 19, 62);
292	      UPDATE_FS_FOR_FR (fs, 20, 64);
293	      UPDATE_FS_FOR_FR (fs, 21, 66);
294	      UPDATE_FS_FOR_FR (fs, 22, 68);
295	      UPDATE_FS_FOR_FR (fs, 23, 70);
296	      UPDATE_FS_FOR_FR (fs, 24, 72);
297	      UPDATE_FS_FOR_FR (fs, 25, 74);
298	      UPDATE_FS_FOR_FR (fs, 26, 76);
299	      UPDATE_FS_FOR_FR (fs, 27, 78);
300	      UPDATE_FS_FOR_FR (fs, 28, 80);
301	      UPDATE_FS_FOR_FR (fs, 29, 82);
302	      UPDATE_FS_FOR_FR (fs, 30, 84);
303	      UPDATE_FS_FOR_FR (fs, 31, 86);
304	    }
305
306	  UPDATE_FS_FOR_SAR (fs, 88);
307	}
308
309      fs->retaddr_column = DWARF_ALT_FRAME_RETURN_COLUMN;
310      UPDATE_FS_FOR_PC (fs, DWARF_ALT_FRAME_RETURN_COLUMN);
311
312      return _URC_NO_REASON;
313    }
314
315  return _URC_END_OF_STACK;
316}
317