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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [config/] [rs6000/] [linux-unwind.h] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 jlechner
/* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux.
2
   Copyright (C) 2004, 2005 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 the current unwind info (FS) does not contain explicit info
93
   saving R2, then we have to do a minor amount of code reading to
94
   figure out if it was saved.  The big problem here is that the
95
   code that does the save/restore is generated by the linker, so
96
   we have no good way to determine at compile time what to do.  */
97
 
98
#define MD_FROB_UPDATE_CONTEXT frob_update_context
99
 
100
static void
101
frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
102
{
103
  if (fs->regs.reg[2].how == REG_UNSAVED)
104
    {
105
      unsigned int *insn
106
        = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
107
      if (*insn == 0xE8410028)
108
        _Unwind_SetGRPtr (context, 2, context->cfa + 40);
109
    }
110
}
111
 
112
/* If PC is at a sigreturn trampoline, return a pointer to the
113
   regs.  Otherwise return NULL.  */
114
 
115
static struct gcc_regs *
116
get_regs (struct _Unwind_Context *context)
117
{
118
  const unsigned char *pc = context->ra;
119
 
120
  /* addi r1, r1, 128; li r0, 0x0077; sc  (sigreturn) */
121
  /* addi r1, r1, 128; li r0, 0x00AC; sc  (rt_sigreturn) */
122
  if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE
123
      || *(unsigned int *) (pc + 8) != 0x44000002)
124
    return NULL;
125
  if (*(unsigned int *) (pc + 4) == 0x38000077)
126
    {
127
      struct sigframe {
128
        char gap[SIGNAL_FRAMESIZE];
129
        unsigned long pad[7];
130
        struct gcc_regs *regs;
131
      } *frame = (struct sigframe *) context->cfa;
132
      return frame->regs;
133
    }
134
  else if (*(unsigned int *) (pc + 4) == 0x380000AC)
135
    {
136
      /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
137
         because pc isn't pointing into the stack.  Can be removed when
138
         no one is running 2.4.19 or 2.4.20, the first two ppc64
139
         kernels released.  */
140
      struct rt_sigframe_24 {
141
        int tramp[6];
142
        void *pinfo;
143
        struct gcc_ucontext *puc;
144
      } *frame24 = (struct rt_sigframe_24 *) pc;
145
 
146
      /* Test for magic value in *puc of vdso.  */
147
      if ((long) frame24->puc != -21 * 8)
148
        return frame24->puc->regs;
149
      else
150
        {
151
          /* This works for 2.4.21 and later kernels.  */
152
          struct rt_sigframe {
153
            char gap[SIGNAL_FRAMESIZE];
154
            struct gcc_ucontext uc;
155
            unsigned long pad[2];
156
            int tramp[6];
157
            void *pinfo;
158
            struct gcc_ucontext *puc;
159
          } *frame = (struct rt_sigframe *) context->cfa;
160
          return frame->uc.regs;
161
        }
162
    }
163
  return NULL;
164
}
165
 
166
#else  /* !__powerpc64__ */
167
 
168
enum { SIGNAL_FRAMESIZE = 64 };
169
 
170
static struct gcc_regs *
171
get_regs (struct _Unwind_Context *context)
172
{
173
  const unsigned char *pc = context->ra;
174
 
175
  /* li r0, 0x7777; sc  (sigreturn old)  */
176
  /* li r0, 0x0077; sc  (sigreturn new)  */
177
  /* li r0, 0x6666; sc  (rt_sigreturn old)  */
178
  /* li r0, 0x00AC; sc  (rt_sigreturn new)  */
179
  if (*(unsigned int *) (pc + 4) != 0x44000002)
180
    return NULL;
181
  if (*(unsigned int *) (pc + 0) == 0x38007777
182
      || *(unsigned int *) (pc + 0) == 0x38000077)
183
    {
184
      struct sigframe {
185
        char gap[SIGNAL_FRAMESIZE];
186
        unsigned long pad[7];
187
        struct gcc_regs *regs;
188
      } *frame = (struct sigframe *) context->cfa;
189
      return frame->regs;
190
    }
191
  else if (*(unsigned int *) (pc + 0) == 0x38006666
192
           || *(unsigned int *) (pc + 0) == 0x380000AC)
193
    {
194
      struct rt_sigframe {
195
        char gap[SIGNAL_FRAMESIZE + 16];
196
        char siginfo[128];
197
        struct gcc_ucontext uc;
198
      } *frame = (struct rt_sigframe *) context->cfa;
199
      return frame->uc.regs;
200
    }
201
  return NULL;
202
}
203
#endif
204
 
205
/* Find an entry in the process auxiliary vector.  The canonical way to
206
   test for VMX is to look at AT_HWCAP.  */
207
 
208
static long
209
ppc_linux_aux_vector (long which)
210
{
211
  /* __libc_stack_end holds the original stack passed to a process.  */
212
  extern long *__libc_stack_end;
213
  long argc;
214
  char **argv;
215
  char **envp;
216
  struct auxv
217
  {
218
    long a_type;
219
    long a_val;
220
  } *auxp;
221
 
222
  /* The Linux kernel puts argc first on the stack.  */
223
  argc = __libc_stack_end[0];
224
  /* Followed by argv, NULL terminated.  */
225
  argv = (char **) __libc_stack_end + 1;
226
  /* Followed by environment string pointers, NULL terminated. */
227
  envp = argv + argc + 1;
228
  while (*envp++)
229
    continue;
230
  /* Followed by the aux vector, zero terminated.  */
231
  for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
232
    if (auxp->a_type == which)
233
      return auxp->a_val;
234
  return 0;
235
}
236
 
237
/* Do code reading to identify a signal frame, and set the frame
238
   state data appropriately.  See unwind-dw2.c for the structs.  */
239
 
240
#define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
241
 
242
static _Unwind_Reason_Code
243
ppc_fallback_frame_state (struct _Unwind_Context *context,
244
                          _Unwind_FrameState *fs)
245
{
246
  static long hwcap = 0;
247
  struct gcc_regs *regs = get_regs (context);
248
  long new_cfa;
249
  int i;
250
 
251
  if (regs == NULL)
252
    return _URC_END_OF_STACK;
253
 
254
  new_cfa = regs->gpr[STACK_POINTER_REGNUM];
255
  fs->cfa_how = CFA_REG_OFFSET;
256
  fs->cfa_reg = STACK_POINTER_REGNUM;
257
  fs->cfa_offset = new_cfa - (long) context->cfa;
258
 
259
  for (i = 0; i < 32; i++)
260
    if (i != STACK_POINTER_REGNUM)
261
      {
262
        fs->regs.reg[i].how = REG_SAVED_OFFSET;
263
        fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
264
      }
265
 
266
  fs->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET;
267
  fs->regs.reg[CR2_REGNO].loc.offset = (long) &regs->ccr - new_cfa;
268
 
269
  fs->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET;
270
  fs->regs.reg[LINK_REGISTER_REGNUM].loc.offset = (long) &regs->link - new_cfa;
271
 
272
  fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
273
  fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) &regs->nip - new_cfa;
274
  fs->retaddr_column = ARG_POINTER_REGNUM;
275
 
276
  if (hwcap == 0)
277
    {
278
      hwcap = ppc_linux_aux_vector (16);
279
      /* These will already be set if we found AT_HWCAP.  A nonzero
280
         value stops us looking again if for some reason we couldn't
281
         find AT_HWCAP.  */
282
#ifdef __powerpc64__
283
      hwcap |= 0xc0000000;
284
#else
285
      hwcap |= 0x80000000;
286
#endif
287
    }
288
 
289
  /* If we have a FPU...  */
290
  if (hwcap & 0x08000000)
291
    for (i = 0; i < 32; i++)
292
      {
293
        fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
294
        fs->regs.reg[i + 32].loc.offset = (long) &regs->fpr[i] - new_cfa;
295
      }
296
 
297
  /* If we have a VMX unit...  */
298
  if (hwcap & 0x10000000)
299
    {
300
      struct gcc_vregs *vregs;
301
#ifdef __powerpc64__
302
      vregs = regs->vp;
303
#else
304
      vregs = &regs->vregs;
305
#endif
306
      if (regs->msr & (1 << 25))
307
        {
308
          for (i = 0; i < 32; i++)
309
            {
310
              fs->regs.reg[i + FIRST_ALTIVEC_REGNO].how = REG_SAVED_OFFSET;
311
              fs->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset
312
                = (long) &vregs[i] - new_cfa;
313
            }
314
 
315
          fs->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET;
316
          fs->regs.reg[VSCR_REGNO].loc.offset = (long) &vregs->vscr - new_cfa;
317
        }
318
 
319
      fs->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET;
320
      fs->regs.reg[VRSAVE_REGNO].loc.offset = (long) &vregs->vsave - new_cfa;
321
    }
322
 
323
  return _URC_NO_REASON;
324
}

powered by: WebSVN 2.1.0

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