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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [rs6000/] [linux-unwind.h] - Blame information for rev 747

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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