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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [rs6000/] [linux-unwind.h] - Blame information for rev 816

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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