sol2-unwind.h revision 1.1
1/* DWARF2 EH unwinding support for SPARC Solaris.
2   Copyright (C) 2009-2013 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 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23<http://www.gnu.org/licenses/>.  */
24
25/* Do code reading to identify a signal frame, and set the frame
26   state data appropriately.  See unwind-dw2.c for the structs.  */
27
28#include <ucontext.h>
29#include <sys/frame.h>
30#include <sys/stack.h>
31
32#ifdef __arch64__
33
34#define IS_SIGHANDLER sparc64_is_sighandler
35
36static int
37sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
38{
39  if (/* Solaris 9 - single-threaded
40	----------------------------
41	The pattern changes slightly in different versions of the
42	operating system, so we skip the comparison against pc[-6] for
43	Solaris 9.
44
45	<sigacthandler+24>:  sra  %i0, 0, %l1
46
47	Solaris 9 5/02:
48	<sigacthandler+28>:  ldx  [ %o2 + 0xf68 ], %g5
49	Solaris 9 9/05:
50	<sigacthandler+28>:  ldx  [ %o2 + 0xe50 ], %g5
51
52	<sigacthandler+32>:  sllx  %l1, 3, %g4
53	<sigacthandler+36>:  mov  %l1, %o0
54	<sigacthandler+40>:  ldx  [ %g4 + %g5 ], %l0
55	<sigacthandler+44>:  call  %l0
56	<sigacthandler+48>:  mov  %i2, %o2
57	<sigacthandler+52>:  cmp  %l1, 8	<--- PC  */
58      (   pc[-7] == 0xa33e2000
59       /* skip pc[-6] */
60       && pc[-5] == 0x892c7003
61       && pc[-4] == 0x90100011
62       && pc[-3] == 0xe0590005
63       && pc[-2] == 0x9fc40000
64       && pc[-1] == 0x9410001a
65       && pc[ 0] == 0x80a46008))
66    {
67      /* We need to move up one frame:
68
69		<signal handler>	<-- context->cfa
70		sigacthandler
71		<kernel>
72      */
73      *nframes = 1;
74      return 1;
75    }
76
77  if (/* Solaris 8+ - multi-threaded
78	----------------------------
79	<__sighndlr>:        save  %sp, -176, %sp
80	<__sighndlr+4>:      mov  %i0, %o0
81	<__sighndlr+8>:      mov  %i1, %o1
82	<__sighndlr+12>:     call  %i3
83	<__sighndlr+16>:     mov  %i2, %o2
84	<__sighndlr+20>:     ret 		<--- PC
85	<__sighndlr+24>:     restore  */
86         pc[-5] == 0x9de3bf50
87      && pc[-4] == 0x90100018
88      && pc[-3] == 0x92100019
89      && pc[-2] == 0x9fc6c000
90      && pc[-1] == 0x9410001a
91      && pc[ 0] == 0x81c7e008
92      && pc[ 1] == 0x81e80000)
93    {
94      /* We have observed different calling frames among different
95	 versions of the operating system, so that we need to
96	 discriminate using the upper frame.  We look for the return
97	 address of the caller frame (there is an offset of 15 double
98	 words between the frame address and the place where this return
99	 address is stored) in order to do some more pattern matching.  */
100      unsigned int cuh_pattern
101	= *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4);
102
103      if (cuh_pattern == 0x92100019)
104	/* This matches the call_user_handler pattern for Solaris 11.
105	   This is the same setup as for Solaris 9, see below.  */
106	*nframes = 3;
107
108      else if (cuh_pattern == 0xd25fa7ef)
109	{
110	  /* This matches the call_user_handler pattern for Solaris 10.
111	     There are 2 cases so we look for the return address of the
112	     caller's caller frame in order to do more pattern matching.  */
113	  unsigned long sah_address = *(unsigned long *)(cfa + 176 + 15*8);
114
115          if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
116	    /* This is the same setup as for Solaris 9, see below.  */
117	    *nframes = 3;
118	  else
119	    /* The sigacthandler frame isn't present in the chain.
120	       We need to move up two frames:
121
122		<signal handler>	<-- context->cfa
123		__sighndlr
124		call_user_handler frame
125		<kernel>
126	    */
127	    *nframes = 2;
128	}
129
130      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
131	/* This matches the call_user_handler pattern for Solaris 9.
132	   We need to move up three frames:
133
134		<signal handler>	<-- context->cfa
135		__sighndlr
136		call_user_handler
137		sigacthandler
138		<kernel>
139	*/
140	*nframes = 3;
141
142      return 1;
143    }
144
145  return 0;
146}
147
148#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
149
150#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
151
152static void
153sparc64_frob_update_context (struct _Unwind_Context *context,
154			     _Unwind_FrameState *fs)
155{
156  /* The column of %sp contains the old CFA, not the old value of %sp.
157     The CFA offset already comprises the stack bias so, when %sp is the
158     CFA register, we must avoid counting the stack bias twice.  Do not
159     do that for signal frames as the offset is artificial for them.  */
160  if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
161      && fs->regs.cfa_how == CFA_REG_OFFSET
162      && fs->regs.cfa_offset != 0
163      && !fs->signal_frame)
164    {
165      long i;
166
167      context->cfa -= STACK_BIAS;
168
169      for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
170	if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
171	  _Unwind_SetGRPtr (context, i,
172			    _Unwind_GetGRPtr (context, i) - STACK_BIAS);
173    }
174}
175
176#else
177
178#define IS_SIGHANDLER sparc_is_sighandler
179
180static int
181sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
182{
183  if (/* Solaris 9 - single-threaded
184        ----------------------------
185	The pattern changes slightly in different versions of the operating
186	system, so we skip the comparison against pc[-6].
187
188	<sigacthandler+16>:  add  %o1, %o7, %o3
189	<sigacthandler+20>:  mov  %i1, %o1
190
191	<sigacthandler+24>:  ld  [ %o3 + <offset> ], %o2
192
193	<sigacthandler+28>:  sll  %i0, 2, %o0
194	<sigacthandler+32>:  ld  [ %o0 + %o2 ], %l0
195	<sigacthandler+36>:  mov  %i0, %o0
196	<sigacthandler+40>:  call  %l0
197	<sigacthandler+44>:  mov  %i2, %o2
198	<sigacthandler+48>:  cmp  %i0, 8	<--- PC  */
199         pc[-8] == 0x9602400f
200      && pc[-7] == 0x92100019
201      /* skip pc[-6] */
202      && pc[-5] == 0x912e2002
203      && pc[-4] == 0xe002000a
204      && pc[-3] == 0x90100018
205      && pc[-2] == 0x9fc40000
206      && pc[-1] == 0x9410001a
207      && pc[ 0] == 0x80a62008)
208    {
209      /* We need to move up one frame:
210
211		<signal handler>	<-- context->cfa
212		sigacthandler
213		<kernel>
214      */
215      *nframes = 1;
216      return 1;
217    }
218
219  if(/* Solaris 8+ - multi-threaded
220       ----------------------------
221       <__sighndlr>:	save  %sp, -96, %sp
222       <__sighndlr+4>:	mov  %i0, %o0
223       <__sighndlr+8>:	mov  %i1, %o1
224       <__sighndlr+12>:	call  %i3
225       <__sighndlr+16>:	mov  %i2, %o2
226       <__sighndlr+20>:	ret 		<--- PC
227       <__sighndlr+24>:	restore  */
228        pc[-5] == 0x9de3bfa0
229     && pc[-4] == 0x90100018
230     && pc[-3] == 0x92100019
231     && pc[-2] == 0x9fc6c000
232     && pc[-1] == 0x9410001a
233     && pc[ 0] == 0x81c7e008
234     && pc[ 1] == 0x81e80000)
235    {
236      /* We have observed different calling frames among different
237	 versions of the operating system, so that we need to
238	 discriminate using the upper frame.  We look for the return
239	 address of the caller frame (there is an offset of 15 words
240	 between the frame address and the place where this return
241	 address is stored) in order to do some more pattern matching.  */
242      unsigned int cuh_pattern
243	= *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4);
244
245      if (cuh_pattern == 0x92100019)
246	/* This matches the call_user_handler pattern for Solaris 11.
247	   This is the same setup as for Solaris 9, see below.  */
248	*nframes = 3;
249
250      else if (cuh_pattern == 0xd407a04c)
251	{
252	  /* This matches the call_user_handler pattern for Solaris 10.
253	     There are 2 cases so we look for the return address of the
254	     caller's caller frame in order to do more pattern matching.  */
255	  unsigned int sah_address = *(unsigned int *)(cfa + 96 + 15*4);
256
257          if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
258	    /* This is the same setup as for Solaris 9, see below.  */
259	    *nframes = 3;
260	  else
261	    /* The sigacthandler frame isn't present in the chain.
262	       We need to move up two frames:
263
264		<signal handler>	<-- context->cfa
265		__sighndlr
266		call_user_handler frame
267		<kernel>
268	    */
269	    *nframes = 2;
270	}
271
272      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
273	/* This matches the call_user_handler pattern for Solaris 9.
274	   We need to move up three frames:
275
276		<signal handler>	<-- context->cfa
277		__sighndlr
278		call_user_handler
279		sigacthandler
280		<kernel>
281	*/
282	*nframes = 3;
283
284      return 1;
285    }
286
287  return 0;
288}
289
290#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
291
292#endif
293
294static _Unwind_Reason_Code
295MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
296			     _Unwind_FrameState *fs)
297{
298  void *pc = context->ra;
299  struct frame *fp = (struct frame *) context->cfa;
300  int nframes;
301  void *this_cfa = context->cfa;
302  long new_cfa;
303  void *ra_location, *shifted_ra_location;
304  mcontext_t *mctx;
305  int i;
306
307  /* Deal with frame-less function from which a signal was raised.  */
308  if (_Unwind_IsSignalFrame (context))
309    {
310      /* The CFA is by definition unmodified in this case.  */
311      fs->regs.cfa_how = CFA_REG_OFFSET;
312      fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
313      fs->regs.cfa_offset = 0;
314
315      /* This is the canonical RA column.  */
316      fs->retaddr_column = 15;
317
318      return _URC_NO_REASON;
319    }
320
321  if (IS_SIGHANDLER (pc, this_cfa, &nframes))
322    {
323      struct handler_args {
324	struct frame frwin;
325	ucontext_t ucontext;
326      } *handler_args;
327      ucontext_t *ucp;
328
329      /* context->cfa points into the frame after the saved frame pointer and
330         saved pc (struct frame).
331
332         The ucontext_t structure is in the kernel frame after a struct
333         frame.  Since the frame sizes vary even within OS releases, we
334         need to walk the stack to get there.  */
335
336      for (i = 0; i < nframes; i++)
337	fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
338
339      handler_args = (struct handler_args *) fp;
340      ucp = &handler_args->ucontext;
341      mctx = &ucp->uc_mcontext;
342    }
343
344  /* Exit if the pattern at the return address does not match the
345     previous three patterns.  */
346  else
347    return _URC_END_OF_STACK;
348
349  new_cfa = mctx->gregs[REG_SP];
350  /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
351  new_cfa += STACK_BIAS;
352
353  fs->regs.cfa_how = CFA_REG_OFFSET;
354  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
355  fs->regs.cfa_offset = new_cfa - (long) this_cfa;
356
357  /* Restore global and out registers (in this order) from the
358     ucontext_t structure, uc_mcontext.gregs field.  */
359  for (i = 1; i < 16; i++)
360    {
361      /* We never restore %sp as everything is purely CFA-based.  */
362      if ((unsigned int) i == __builtin_dwarf_sp_column ())
363	continue;
364
365      /* First the global registers and then the out registers.  */
366      fs->regs.reg[i].how = REG_SAVED_OFFSET;
367      fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
368    }
369
370  /* Just above the stack pointer there are 16 extended words in which
371     the register window (in and local registers) was saved.  */
372  for (i = 0; i < 16; i++)
373    {
374      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
375      fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
376    }
377
378  /* Check whether we need to restore FPU registers.  */
379  if (mctx->fpregs.fpu_qcnt)
380    {
381      for (i = 0; i < 32; i++)
382	{
383	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
384	  fs->regs.reg[i + 32].loc.offset
385	    = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
386	}
387
388#ifdef __arch64__
389      /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles.  */
390      for (i = 32; i < 64; i++)
391	{
392	  if (i > 32 && (i & 1))
393	    continue;
394
395	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
396	  fs->regs.reg[i + 32].loc.offset
397	    = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
398	}
399#endif
400    }
401
402  /* State the rules to find the kernel's code "return address", which is
403     the address of the active instruction when the signal was caught.
404     On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
405     need to preventively subtract it from the purported return address.  */
406  ra_location = &mctx->gregs[REG_PC];
407  shifted_ra_location = &mctx->gregs[REG_Y];
408  *(void **)shifted_ra_location = *(void **)ra_location - 8;
409  fs->retaddr_column = 0;
410  fs->regs.reg[0].how = REG_SAVED_OFFSET;
411  fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
412  fs->signal_frame = 1;
413
414  return _URC_NO_REASON;
415}
416