aix-unwind.h revision 1.1
1/* DWARF2 EH unwinding support for AIX.
2   Copyright (C) 2011-2013 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 it
7   under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   GCC is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14   License for more details.
15
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.
19
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/>.  */
24
25/* Useful register numbers.  */
26
27#define LR_REGNO             65
28#define CR2_REGNO            70
29#define XER_REGNO            76
30#define FIRST_ALTIVEC_REGNO  77
31#define VRSAVE_REGNO        109
32#define VSCR_REGNO          110
33
34/* If the current unwind info (FS) does not contain explicit info
35   saving R2, then we have to do a minor amount of code reading to
36   figure out if it was saved.  The big problem here is that the
37   code that does the save/restore is generated by the linker, so
38   we have no good way to determine at compile time what to do.  */
39
40#ifdef __64BIT__
41#define MD_FROB_UPDATE_CONTEXT(CTX, FS)					\
42  do {									\
43    if ((FS)->regs.reg[2].how == REG_UNSAVED)				\
44      {									\
45	unsigned int *insn						\
46	  = (unsigned int *)						\
47	    _Unwind_GetGR ((CTX), LR_REGNO);				\
48	if (*insn == 0xE8410028)					\
49	  _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40);			\
50      }									\
51  } while (0)
52#else
53#define MD_FROB_UPDATE_CONTEXT(CTX, FS)					\
54  do {									\
55    if ((FS)->regs.reg[2].how == REG_UNSAVED)				\
56      {									\
57	unsigned int *insn						\
58	  = (unsigned int *)						\
59	    _Unwind_GetGR ((CTX), LR_REGNO);				\
60	if (*insn == 0x80410014)					\
61	  _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20);			\
62      }									\
63  } while (0)
64#endif
65
66/* Now on to MD_FALLBACK_FRAME_STATE_FOR.
67   32bit AIX 5.2 and 5.3 only at this stage.  */
68
69#include <stdlib.h>
70#include <stddef.h>
71#include <signal.h>
72#include <sys/machine.h>
73
74#ifdef __64BIT__
75
76/* 64bit fallback not implemented yet, so MD_FALLBACK_FRAME_STATE_FOR not
77   defined.  Arrange just for the code below to compile.  */
78typedef struct __context64 mstate_t;
79
80#else
81
82typedef struct mstsave mstate_t;
83
84#define MD_FALLBACK_FRAME_STATE_FOR ppc_aix_fallback_frame_state
85
86#endif
87
88/* If we are compiling on AIX < 5.3, the VMX related datastructs are not
89   defined and we take measures to obtain proper runtime behavior if the
90   compiled code happens to run on a later version with VMX enabled.  */
91
92#ifndef MSR_VMX
93#define MSR_VMX 0x2000000
94#endif
95
96typedef unsigned int uint;
97typedef struct { uint v[4]; } vreg_t;
98typedef struct {
99  vreg_t regs[32];
100  uint   pad1 [3];
101  uint   vscr;
102  uint   vrsave;
103  uint   pad2 [3];
104} vstate_t;
105
106#define EXT_CONTEXT_MARK 0x45435458
107#define EXT_CONTEXT_SIZE 4096
108#define BUMPER_SIZE (EXT_CONTEXT_SIZE - sizeof(vstate_t) - (5 * sizeof(int)))
109
110typedef struct {
111  uint     pad1 [4];
112  vstate_t vstate;
113  char     bumper [BUMPER_SIZE];
114  int      mark;
115} extended_context_t;
116
117typedef struct {
118  char bumper [offsetof (ucontext_t, uc_stack) + sizeof (stack_t)];
119  extended_context_t * ectx;
120  int mark;
121} vmx_ucontext_t;
122
123/* Determine whether CONTEXT designates a signal handler, and return the
124   associated ucontext_t address if so.  Return NULL otherwise.  */
125
126static ucontext_t *
127ucontext_for (struct _Unwind_Context *context)
128{
129  const unsigned int * ra = context->ra;
130
131  /* AIX 5.2 and 5.3, threaded or not, share common patterns and feature
132     variants depending on the configured kernel (unix_mp or unix_64).  */
133
134  if (*(ra - 5) == 0x4c00012c     /* isync             */
135      && *(ra - 4) == 0x80ec0000  /* lwz     r7,0(r12) */
136      && *(ra - 3) == 0x804c0004  /* lwz     r2,4(r12) */
137      && *(ra - 2) == 0x7ce903a6  /* mtctr   r7        */
138      && *(ra - 1) == 0x4e800421  /* bctrl             */
139      && *(ra - 0) == 0x7dc37378) /* mr      r3,r14   <-- context->ra */
140    {
141      /* unix_64 */
142      if (*(ra - 6) == 0x7d000164)  /* mtmsrd  r8 */
143	{
144	  switch (*(ra + 18))
145	    {
146	      /* AIX 5.2 */
147	    case 0x835a0520: /* lwz r26,1312(r26) */
148	      return (ucontext_t *)(context->cfa + 0x70);
149
150	      /* AIX 5.3 */
151	    case 0x835a0570:  /* lwz r26,1392(r26) */
152	      return (ucontext_t *)(context->cfa + 0x40);
153
154	    default:
155	      return 0;
156	    }
157	}
158
159      /* unix_mp */
160      if (*(ra - 6) == 0x7d000124)  /* mtmsr  r8 */
161	{
162	  typedef struct {
163	    char pad[56];
164	    ucontext_t ucontext;
165	    siginfo_t siginfo;
166	  } aix52_stack_t;
167
168	  aix52_stack_t * frame = (aix52_stack_t *) context->cfa;
169	  return &frame->ucontext;
170	}
171    }
172
173  return 0;
174}
175
176/* The fallback proper.  */
177
178#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
179#define RETURN_COLUMN DWARF_ALT_FRAME_RETURN_COLUMN
180#else
181#define RETURN_COLUMN ARG_POINTER_REGNUM
182#endif
183
184#define REGISTER_CFA_OFFSET_FOR(FS,REGNO,ADDR,CFA)\
185do { \
186(FS)->regs.reg[REGNO].how = REG_SAVED_OFFSET; \
187(FS)->regs.reg[REGNO].loc.offset = (long) (ADDR) - (CFA); \
188} while (0);
189
190static _Unwind_Reason_Code
191ppc_aix_fallback_frame_state (struct _Unwind_Context *context,
192			      _Unwind_FrameState *fs)
193{
194  ucontext_t * uctx = ucontext_for (context);
195  mstate_t * mctx;
196
197  long new_cfa;
198  int i;
199
200  if (uctx == NULL)
201    return _URC_END_OF_STACK;
202
203  mctx = &uctx->uc_mcontext.jmp_context;
204
205  /* The "kernel" frame cfa is the stack pointer at the signal occurrence
206     point.  */
207  new_cfa = mctx->gpr[STACK_POINTER_REGNUM];
208
209  fs->regs.cfa_how = CFA_REG_OFFSET;
210  fs->regs.cfa_reg = STACK_POINTER_REGNUM;
211  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
212
213  /* And we state how to find the various registers it has saved with
214     relative offset rules from there.  */
215
216  for (i = 0; i < 32; i++)
217    if (i != STACK_POINTER_REGNUM)
218      REGISTER_CFA_OFFSET_FOR (fs, i, &mctx->gpr[i], new_cfa);
219
220  REGISTER_CFA_OFFSET_FOR (fs, CR2_REGNO, &mctx->cr, new_cfa);
221  REGISTER_CFA_OFFSET_FOR (fs, XER_REGNO, &mctx->xer, new_cfa);
222  REGISTER_CFA_OFFSET_FOR (fs, LR_REGNO, &mctx->lr, new_cfa);
223
224  fs->retaddr_column = RETURN_COLUMN;
225  REGISTER_CFA_OFFSET_FOR (fs, RETURN_COLUMN, &mctx->iar, new_cfa);
226  fs->signal_frame = 1;
227
228  /* Honor FP Ever Used ...   */
229  if (mctx->fpeu)
230    {
231      for (i = 0; i < 32; i++)
232	REGISTER_CFA_OFFSET_FOR (fs, i+32, &mctx->fpr[i], new_cfa);
233    }
234
235  /* Honor VMX context, if any.  We expect the msr bit never to be set in
236     environments where there is no VMX support, e.g. on AIX < 5.3.  */
237  if (mctx->msr & MSR_VMX)
238    {
239      vmx_ucontext_t * uc = (vmx_ucontext_t *) uctx;
240
241      if (uc->mark == EXT_CONTEXT_MARK && uc->ectx->mark == EXT_CONTEXT_MARK)
242	{
243	  vstate_t * vstate = &uc->ectx->vstate;
244
245	  for (i = 0; i < 32; i++)
246	    REGISTER_CFA_OFFSET_FOR
247	    (fs, i+FIRST_ALTIVEC_REGNO, &vstate->regs[i], new_cfa);
248
249	  REGISTER_CFA_OFFSET_FOR (fs, VSCR_REGNO, &vstate->vscr, new_cfa);
250	  REGISTER_CFA_OFFSET_FOR (fs, VRSAVE_REGNO, &vstate->vrsave, new_cfa);
251	}
252    }
253
254  return _URC_NO_REASON;
255}
256