OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [rs6000/] [linux-unwind.h] - Blame information for rev 282

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 282 jeremybenn
/* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2
   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 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
8
   by the Free Software Foundation; either version 3, or (at your
9
   option) 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
#define R_LR            65
26
#define R_CR2           70
27
#define R_VR0           77
28
#define R_VRSAVE        109
29
#define R_VSCR          110
30
 
31
struct gcc_vregs
32
{
33
  __attribute__ ((vector_size (16))) int vr[32];
34
#ifdef __powerpc64__
35
  unsigned int pad1[3];
36
  unsigned int vscr;
37
  unsigned int vsave;
38
  unsigned int pad2[3];
39
#else
40
  unsigned int vsave;
41
  unsigned int pad[2];
42
  unsigned int vscr;
43
#endif
44
};
45
 
46
struct gcc_regs
47
{
48
  unsigned long gpr[32];
49
  unsigned long nip;
50
  unsigned long msr;
51
  unsigned long orig_gpr3;
52
  unsigned long ctr;
53
  unsigned long link;
54
  unsigned long xer;
55
  unsigned long ccr;
56
  unsigned long softe;
57
  unsigned long trap;
58
  unsigned long dar;
59
  unsigned long dsisr;
60
  unsigned long result;
61
  unsigned long pad1[4];
62
  double fpr[32];
63
  unsigned int pad2;
64
  unsigned int fpscr;
65
#ifdef __powerpc64__
66
  struct gcc_vregs *vp;
67
#else
68
  unsigned int pad3[2];
69
#endif
70
  struct gcc_vregs vregs;
71
};
72
 
73
struct gcc_ucontext
74
{
75
#ifdef __powerpc64__
76
  unsigned long pad[28];
77
#else
78
  unsigned long pad[12];
79
#endif
80
  struct gcc_regs *regs;
81
  struct gcc_regs rsave;
82
};
83
 
84
#ifdef __powerpc64__
85
 
86
enum { SIGNAL_FRAMESIZE = 128 };
87
 
88
/* If PC is at a sigreturn trampoline, return a pointer to the
89
   regs.  Otherwise return NULL.  */
90
 
91
static struct gcc_regs *
92
get_regs (struct _Unwind_Context *context)
93
{
94
  const unsigned int *pc = context->ra;
95
 
96
  /* addi r1, r1, 128; li r0, 0x0077; sc  (sigreturn) */
97
  /* addi r1, r1, 128; li r0, 0x00AC; sc  (rt_sigreturn) */
98
  if (pc[0] != 0x38210000 + SIGNAL_FRAMESIZE || pc[2] != 0x44000002)
99
    return NULL;
100
  if (pc[1] == 0x38000077)
101
    {
102
      struct sigframe {
103
        char gap[SIGNAL_FRAMESIZE];
104
        unsigned long pad[7];
105
        struct gcc_regs *regs;
106
      } *frame = (struct sigframe *) context->cfa;
107
      return frame->regs;
108
    }
109
  else if (pc[1] == 0x380000AC)
110
    {
111
      /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
112
         because pc isn't pointing into the stack.  Can be removed when
113
         no one is running 2.4.19 or 2.4.20, the first two ppc64
114
         kernels released.  */
115
      const struct rt_sigframe_24 {
116
        int tramp[6];
117
        void *pinfo;
118
        struct gcc_ucontext *puc;
119
      } *frame24 = (const struct rt_sigframe_24 *) context->ra;
120
 
121
      /* Test for magic value in *puc of vdso.  */
122
      if ((long) frame24->puc != -21 * 8)
123
        return frame24->puc->regs;
124
      else
125
        {
126
          /* This works for 2.4.21 and later kernels.  */
127
          struct rt_sigframe {
128
            char gap[SIGNAL_FRAMESIZE];
129
            struct gcc_ucontext uc;
130
            unsigned long pad[2];
131
            int tramp[6];
132
            void *pinfo;
133
            struct gcc_ucontext *puc;
134
          } *frame = (struct rt_sigframe *) context->cfa;
135
          return frame->uc.regs;
136
        }
137
    }
138
  return NULL;
139
}
140
 
141
#else  /* !__powerpc64__ */
142
 
143
enum { SIGNAL_FRAMESIZE = 64 };
144
 
145
static struct gcc_regs *
146
get_regs (struct _Unwind_Context *context)
147
{
148
  const unsigned int *pc = context->ra;
149
 
150
  /* li r0, 0x7777; sc  (sigreturn old)  */
151
  /* li r0, 0x0077; sc  (sigreturn new)  */
152
  /* li r0, 0x6666; sc  (rt_sigreturn old)  */
153
  /* li r0, 0x00AC; sc  (rt_sigreturn new)  */
154
  if (pc[1] != 0x44000002)
155
    return NULL;
156
  if (pc[0] == 0x38007777 || pc[0] == 0x38000077)
157
    {
158
      struct sigframe {
159
        char gap[SIGNAL_FRAMESIZE];
160
        unsigned long pad[7];
161
        struct gcc_regs *regs;
162
      } *frame = (struct sigframe *) context->cfa;
163
      return frame->regs;
164
    }
165
  else if (pc[0] == 0x38006666 || pc[0] == 0x380000AC)
166
    {
167
      struct rt_sigframe {
168
        char gap[SIGNAL_FRAMESIZE + 16];
169
        char siginfo[128];
170
        struct gcc_ucontext uc;
171
      } *frame = (struct rt_sigframe *) context->cfa;
172
      return frame->uc.regs;
173
    }
174
  return NULL;
175
}
176
#endif
177
 
178
/* Find an entry in the process auxiliary vector.  The canonical way to
179
   test for VMX is to look at AT_HWCAP.  */
180
 
181
static long
182
ppc_linux_aux_vector (long which)
183
{
184
  /* __libc_stack_end holds the original stack passed to a process.  */
185
  extern long *__libc_stack_end;
186
  long argc;
187
  char **argv;
188
  char **envp;
189
  struct auxv
190
  {
191
    long a_type;
192
    long a_val;
193
  } *auxp;
194
 
195
  /* The Linux kernel puts argc first on the stack.  */
196
  argc = __libc_stack_end[0];
197
  /* Followed by argv, NULL terminated.  */
198
  argv = (char **) __libc_stack_end + 1;
199
  /* Followed by environment string pointers, NULL terminated. */
200
  envp = argv + argc + 1;
201
  while (*envp++)
202
    continue;
203
  /* Followed by the aux vector, zero terminated.  */
204
  for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
205
    if (auxp->a_type == which)
206
      return auxp->a_val;
207
  return 0;
208
}
209
 
210
/* Do code reading to identify a signal frame, and set the frame
211
   state data appropriately.  See unwind-dw2.c for the structs.  */
212
 
213
#define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
214
 
215
static _Unwind_Reason_Code
216
ppc_fallback_frame_state (struct _Unwind_Context *context,
217
                          _Unwind_FrameState *fs)
218
{
219
  static long hwcap = 0;
220
  struct gcc_regs *regs = get_regs (context);
221
  long new_cfa;
222
  int i;
223
 
224
  if (regs == NULL)
225
    return _URC_END_OF_STACK;
226
 
227
  new_cfa = regs->gpr[STACK_POINTER_REGNUM];
228
  fs->regs.cfa_how = CFA_REG_OFFSET;
229
  fs->regs.cfa_reg = STACK_POINTER_REGNUM;
230
  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
231
 
232
  for (i = 0; i < 32; i++)
233
    if (i != STACK_POINTER_REGNUM)
234
      {
235
        fs->regs.reg[i].how = REG_SAVED_OFFSET;
236
        fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
237
      }
238
 
239
  fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
240
  /* CR? regs are always 32-bit and PPC is big-endian, so in 64-bit
241
     libgcc loc.offset needs to point to the low 32 bits of regs->ccr.  */
242
  fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa
243
                                   + sizeof (long) - 4;
244
 
245
  fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
246
  fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
247
 
248
  fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
249
  fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
250
  fs->retaddr_column = ARG_POINTER_REGNUM;
251
  fs->signal_frame = 1;
252
 
253
  if (hwcap == 0)
254
    {
255
      hwcap = ppc_linux_aux_vector (16);
256
      /* These will already be set if we found AT_HWCAP.  A nonzero
257
         value stops us looking again if for some reason we couldn't
258
         find AT_HWCAP.  */
259
#ifdef __powerpc64__
260
      hwcap |= 0xc0000000;
261
#else
262
      hwcap |= 0x80000000;
263
#endif
264
    }
265
 
266
  /* If we have a FPU...  */
267
  if (hwcap & 0x08000000)
268
    for (i = 0; i < 32; i++)
269
      {
270
        fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
271
        fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
272
      }
273
 
274
  /* If we have a VMX unit...  */
275
  if (hwcap & 0x10000000)
276
    {
277
      struct gcc_vregs *vregs;
278
#ifdef __powerpc64__
279
      vregs = regs->vp;
280
#else
281
      vregs = &regs->vregs;
282
#endif
283
      if (regs->msr & (1 << 25))
284
        {
285
          for (i = 0; i < 32; i++)
286
            {
287
              fs->regs.reg[i + R_VR0].how = REG_SAVED_OFFSET;
288
              fs->regs.reg[i + R_VR0].loc.offset
289
                = (long) &vregs->vr[i] - new_cfa;
290
            }
291
 
292
          fs->regs.reg[R_VSCR].how = REG_SAVED_OFFSET;
293
          fs->regs.reg[R_VSCR].loc.offset = (long) &vregs->vscr - new_cfa;
294
        }
295
 
296
      fs->regs.reg[R_VRSAVE].how = REG_SAVED_OFFSET;
297
      fs->regs.reg[R_VRSAVE].loc.offset = (long) &vregs->vsave - new_cfa;
298
    }
299
 
300
  /* If we have SPE register high-parts... we check at compile-time to
301
     avoid expanding the code for all other PowerPC.  */
302
#ifdef __SPE__
303
  for (i = 0; i < 32; i++)
304
    {
305
      fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].how = REG_SAVED_OFFSET;
306
      fs->regs.reg[i + FIRST_PSEUDO_REGISTER - 1].loc.offset
307
        = (long) &regs->vregs - new_cfa + 4 * i;
308
    }
309
#endif
310
 
311
  return _URC_NO_REASON;
312
}
313
 
314
#define MD_FROB_UPDATE_CONTEXT frob_update_context
315
 
316
static void
317
frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
318
{
319
  const unsigned int *pc = (const unsigned int *) context->ra;
320
 
321
  /* Fix up for 2.6.12 - 2.6.16 Linux kernels that have vDSO, but don't
322
     have S flag in it.  */
323
#ifdef __powerpc64__
324
  /* addi r1, r1, 128; li r0, 0x0077; sc  (sigreturn) */
325
  /* addi r1, r1, 128; li r0, 0x00AC; sc  (rt_sigreturn) */
326
  if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
327
      && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
328
      && pc[2] == 0x44000002)
329
    _Unwind_SetSignalFrame (context, 1);
330
#else
331
  /* li r0, 0x7777; sc  (sigreturn old)  */
332
  /* li r0, 0x0077; sc  (sigreturn new)  */
333
  /* li r0, 0x6666; sc  (rt_sigreturn old)  */
334
  /* li r0, 0x00AC; sc  (rt_sigreturn new)  */
335
  if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
336
       || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
337
      && pc[1] == 0x44000002)
338
    _Unwind_SetSignalFrame (context, 1);
339
#endif
340
 
341
#ifdef __powerpc64__
342
  if (fs->regs.reg[2].how == REG_UNSAVED)
343
    {
344
      /* If the current unwind info (FS) does not contain explicit info
345
         saving R2, then we have to do a minor amount of code reading to
346
         figure out if it was saved.  The big problem here is that the
347
         code that does the save/restore is generated by the linker, so
348
         we have no good way to determine at compile time what to do.  */
349
      unsigned int *insn
350
        = (unsigned int *) _Unwind_GetGR (context, R_LR);
351
      if (insn && *insn == 0xE8410028)
352
        _Unwind_SetGRPtr (context, 2, context->cfa + 40);
353
    }
354
#endif
355
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.