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/] [darwin-fallback.c] - Blame information for rev 461

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

Line No. Rev Author Line
1 282 jeremybenn
/* Fallback frame-state unwinder for Darwin.
2
   Copyright (C) 2004, 2005, 2007, 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 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
#ifdef __ppc__
26
 
27
#include "tconfig.h"
28
#include "tsystem.h"
29
#include "coretypes.h"
30
#include "tm.h"
31
#include "dwarf2.h"
32
#include "unwind.h"
33
#include "unwind-dw2.h"
34
#include <stdint.h>
35
#include <stdbool.h>
36
#include <sys/types.h>
37
#include <signal.h>
38
 
39
#define R_LR            65
40
#define R_CTR           66
41
#define R_CR2           70
42
#define R_XER           76
43
#define R_VR0           77
44
#define R_VRSAVE        109
45
#define R_VSCR          110
46
#define R_SPEFSCR       112
47
 
48
typedef unsigned long reg_unit;
49
 
50
/* Place in GPRS the parameters to the first 'sc' instruction that would
51
   have been executed if we were returning from this CONTEXT, or
52
   return false if an unexpected instruction is encountered.  */
53
 
54
static bool
55
interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
56
{
57
  uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
58
  uint32_t cr;
59
  reg_unit lr = (reg_unit) pc;
60
  reg_unit ctr = 0;
61
  uint32_t *invalid_address = NULL;
62
 
63
  int i;
64
 
65
  for (i = 0; i < 13; i++)
66
    gprs[i] = 1;
67
  gprs[1] = _Unwind_GetCFA (context);
68
  for (; i < 32; i++)
69
    gprs[i] = _Unwind_GetGR (context, i);
70
  cr = _Unwind_GetGR (context, R_CR2);
71
 
72
  /* For each supported Libc, we have to track the code flow
73
     all the way back into the kernel.
74
 
75
     This code is believed to support all released Libc/Libsystem builds since
76
     Jaguar 6C115, including all the security updates.  To be precise,
77
 
78
     Libc       Libsystem       Build(s)
79
     262~1      60~37           6C115
80
     262~1      60.2~4          6D52
81
     262~1      61~3            6F21-6F22
82
     262~1      63~24           6G30-6G37
83
     262~1      63~32           6I34-6I35
84
     262~1      63~64           6L29-6L60
85
     262.4.1~1  63~84           6L123-6R172
86
 
87
     320~1      71~101          7B85-7D28
88
     320~1      71~266          7F54-7F56
89
     320~1      71~288          7F112
90
     320~1      71~289          7F113
91
     320.1.3~1  71.1.1~29       7H60-7H105
92
     320.1.3~1  71.1.1~30       7H110-7H113
93
     320.1.3~1  71.1.1~31       7H114
94
 
95
     That's a big table!  It would be insane to try to keep track of
96
     every little detail, so we just read the code itself and do what
97
     it would do.
98
  */
99
 
100
  for (;;)
101
    {
102
      uint32_t ins = *pc++;
103
 
104
      if ((ins & 0xFC000003) == 0x48000000)  /* b instruction */
105
        {
106
          pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
107
          continue;
108
        }
109
      if ((ins & 0xFC600000) == 0x2C000000)  /* cmpwi */
110
        {
111
          int32_t val1 = (int16_t) ins;
112
          int32_t val2 = gprs[ins >> 16 & 0x1F];
113
          /* Only beq and bne instructions are supported, so we only
114
             need to set the EQ bit.  */
115
          uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C);
116
          if (val1 == val2)
117
            cr |= mask;
118
          else
119
            cr &= ~mask;
120
          continue;
121
        }
122
      if ((ins & 0xFEC38003) == 0x40820000)  /* forwards beq/bne */
123
        {
124
          if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
125
            pc += (ins & 0x7FFC) / 4 - 1;
126
          continue;
127
        }
128
      if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
129
        {
130
          gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F]
131
                                     | gprs [ins >> 21 & 0x1F]);
132
          continue;
133
        }
134
      if (ins >> 26 == 0x0E)  /* addi, including li */
135
        {
136
          reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
137
          gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
138
          continue;
139
        }
140
      if (ins >> 26 == 0x0F)  /* addis, including lis */
141
        {
142
          reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
143
          gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
144
          continue;
145
        }
146
      if (ins >> 26 == 0x20)  /* lwz */
147
        {
148
          reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
149
          uint32_t *p = (uint32_t *)(src + (int16_t) ins);
150
          if (p == invalid_address)
151
            return false;
152
          gprs [ins >> 21 & 0x1F] = *p;
153
          continue;
154
        }
155
      if (ins >> 26 == 0x21)  /* lwzu */
156
        {
157
          uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
158
          if (p == invalid_address)
159
            return false;
160
          gprs [ins >> 21 & 0x1F] = *p;
161
          continue;
162
        }
163
      if (ins >> 26 == 0x24)  /* stw */
164
        /* What we hope this is doing is '--in_sigtramp'.  We don't want
165
           to actually store to memory, so just make a note of the
166
           address and refuse to load from it.  */
167
        {
168
          reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
169
          uint32_t *p = (uint32_t *)(src + (int16_t) ins);
170
          if (p == NULL || invalid_address != NULL)
171
            return false;
172
          invalid_address = p;
173
          continue;
174
        }
175
      if (ins >> 26 == 0x2E) /* lmw */
176
        {
177
          reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
178
          uint32_t *p = (uint32_t *)(src + (int16_t) ins);
179
          int i;
180
 
181
          for (i = (ins >> 21 & 0x1F); i < 32; i++)
182
            {
183
              if (p == invalid_address)
184
                return false;
185
              gprs[i] = *p++;
186
            }
187
          continue;
188
        }
189
      if ((ins & 0xFC1FFFFF) == 0x7c0803a6)  /* mtlr */
190
        {
191
          lr = gprs [ins >> 21 & 0x1F];
192
          continue;
193
        }
194
      if ((ins & 0xFC1FFFFF) == 0x7c0802a6)  /* mflr */
195
        {
196
          gprs [ins >> 21 & 0x1F] = lr;
197
          continue;
198
        }
199
      if ((ins & 0xFC1FFFFF) == 0x7c0903a6)  /* mtctr */
200
        {
201
          ctr = gprs [ins >> 21 & 0x1F];
202
          continue;
203
        }
204
      /* The PowerPC User's Manual says that bit 11 of the mtcrf
205
         instruction is reserved and should be set to zero, but it
206
         looks like the Darwin assembler doesn't do that... */
207
      if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */
208
        {
209
          int i;
210
          uint32_t mask = 0;
211
          for (i = 0; i < 8; i++)
212
            mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i;
213
          cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask);
214
          continue;
215
        }
216
      if (ins == 0x429f0005)  /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
217
        {
218
          lr = (reg_unit) pc;
219
          continue;
220
        }
221
      if (ins == 0x4e800420) /* bctr */
222
        {
223
          pc = (uint32_t *) ctr;
224
          continue;
225
        }
226
      if (ins == 0x44000002) /* sc */
227
        return true;
228
 
229
      return false;
230
    }
231
}
232
 
233
/* We used to include <ucontext.h> and <mach/thread_status.h>,
234
   but they change so much between different Darwin system versions
235
   that it's much easier to just write the structures involved here
236
   directly.  */
237
 
238
/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c.  */
239
#define UC_TRAD                 1
240
#define UC_TRAD_VEC             6
241
#define UC_TRAD64               20
242
#define UC_TRAD64_VEC           25
243
#define UC_FLAVOR               30
244
#define UC_FLAVOR_VEC           35
245
#define UC_FLAVOR64             40
246
#define UC_FLAVOR64_VEC         45
247
#define UC_DUAL                 50
248
#define UC_DUAL_VEC             55
249
 
250
struct gcc_ucontext
251
{
252
  int onstack;
253
  sigset_t sigmask;
254
  void * stack_sp;
255
  size_t stack_sz;
256
  int stack_flags;
257
  struct gcc_ucontext *link;
258
  size_t mcsize;
259
  struct gcc_mcontext32 *mcontext;
260
};
261
 
262
struct gcc_float_vector_state
263
{
264
  double fpregs[32];
265
  uint32_t fpscr_pad;
266
  uint32_t fpscr;
267
  uint32_t save_vr[32][4];
268
  uint32_t save_vscr[4];
269
};
270
 
271
struct gcc_mcontext32 {
272
  uint32_t dar;
273
  uint32_t dsisr;
274
  uint32_t exception;
275
  uint32_t padding1[5];
276
  uint32_t srr0;
277
  uint32_t srr1;
278
  uint32_t gpr[32];
279
  uint32_t cr;
280
  uint32_t xer;
281
  uint32_t lr;
282
  uint32_t ctr;
283
  uint32_t mq;
284
  uint32_t vrsave;
285
  struct gcc_float_vector_state fvs;
286
};
287
 
288
/* These are based on /usr/include/ppc/ucontext.h and
289
   /usr/include/mach/ppc/thread_status.h, but rewritten to be more
290
   convenient, to compile on Jaguar, and to work around Radar 3712064
291
   on Panther, which is that the 'es' field of 'struct mcontext64' has
292
   the wrong type (doh!).  */
293
 
294
struct gcc_mcontext64 {
295
  uint64_t dar;
296
  uint32_t dsisr;
297
  uint32_t exception;
298
  uint32_t padding1[4];
299
  uint64_t srr0;
300
  uint64_t srr1;
301
  uint32_t gpr[32][2];
302
  uint32_t cr;
303
  uint32_t xer[2];  /* These are arrays because the original structure has them misaligned.  */
304
  uint32_t lr[2];
305
  uint32_t ctr[2];
306
  uint32_t vrsave;
307
  struct gcc_float_vector_state fvs;
308
};
309
 
310
#define UC_FLAVOR_SIZE \
311
  (sizeof (struct gcc_mcontext32) - 33*16)
312
 
313
#define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32))
314
 
315
#define UC_FLAVOR64_SIZE \
316
  (sizeof (struct gcc_mcontext64) - 33*16)
317
 
318
#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
319
 
320
/* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
321
   to represent the execution of a signal return; or, if not a signal
322
   return, return false.  */
323
 
324
static bool
325
handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
326
                _Unwind_Ptr old_cfa)
327
{
328
  struct gcc_ucontext *uctx;
329
  bool is_64, is_vector;
330
  struct gcc_float_vector_state * float_vector_state;
331
  _Unwind_Ptr new_cfa;
332
  int i;
333
  static _Unwind_Ptr return_addr;
334
 
335
  /* Yay!  We're in a Libc that we understand, and it's made a
336
     system call.  In Jaguar, this is a direct system call with value 103;
337
     in Panther and Tiger it is a SYS_syscall call for system call number 184,
338
     and in Leopard it is a direct syscall with number 184.  */
339
 
340
  if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
341
    {
342
      uctx = (struct gcc_ucontext *) gprs[3];
343
      is_vector = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
344
                   || uctx->mcsize == UC_FLAVOR_VEC_SIZE);
345
      is_64 = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE
346
               || uctx->mcsize == UC_FLAVOR64_SIZE);
347
    }
348
  else if (gprs[0] == 0 /* SYS_syscall */ && gprs[3] == 184)
349
    {
350
      int ctxstyle = gprs[5];
351
      uctx = (struct gcc_ucontext *) gprs[4];
352
      is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
353
                   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
354
      is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
355
               || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
356
    }
357
  else if (gprs[0] == 184 /* SYS_sigreturn */)
358
    {
359
      int ctxstyle = gprs[4];
360
      uctx = (struct gcc_ucontext *) gprs[3];
361
      is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
362
                   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
363
      is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
364
               || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
365
    }
366
  else
367
    return false;
368
 
369
#define set_offset(r, addr)                                     \
370
  (fs->regs.reg[r].how = REG_SAVED_OFFSET,                      \
371
   fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
372
 
373
  /* Restore even the registers that are not call-saved, since they
374
     might be being used in the prologue to save other registers,
375
     for instance GPR0 is sometimes used to save LR.  */
376
 
377
  /* Handle the GPRs, and produce the information needed to do the rest.  */
378
  if (is_64)
379
    {
380
      /* The context is 64-bit, but it doesn't carry any extra information
381
         for us because only the low 32 bits of the registers are
382
         call-saved.  */
383
      struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext;
384
      int i;
385
 
386
      float_vector_state = &m64->fvs;
387
 
388
      new_cfa = m64->gpr[1][1];
389
 
390
      set_offset (R_CR2, &m64->cr);
391
      for (i = 0; i < 32; i++)
392
        set_offset (i, m64->gpr[i] + 1);
393
      set_offset (R_XER, m64->xer + 1);
394
      set_offset (R_LR, m64->lr + 1);
395
      set_offset (R_CTR, m64->ctr + 1);
396
      if (is_vector)
397
        set_offset (R_VRSAVE, &m64->vrsave);
398
 
399
      /* Sometimes, srr0 points to the instruction that caused the exception,
400
         and sometimes to the next instruction to be executed; we want
401
         the latter.  */
402
      if (m64->exception == 3 || m64->exception == 4
403
          || m64->exception == 6
404
          || (m64->exception == 7 && !(m64->srr1 & 0x10000)))
405
        return_addr = m64->srr0 + 4;
406
      else
407
        return_addr = m64->srr0;
408
    }
409
  else
410
    {
411
      struct gcc_mcontext32 *m = uctx->mcontext;
412
      int i;
413
 
414
      float_vector_state = &m->fvs;
415
 
416
      new_cfa = m->gpr[1];
417
 
418
      set_offset (R_CR2, &m->cr);
419
      for (i = 0; i < 32; i++)
420
        set_offset (i, m->gpr + i);
421
      set_offset (R_XER, &m->xer);
422
      set_offset (R_LR, &m->lr);
423
      set_offset (R_CTR, &m->ctr);
424
 
425
      if (is_vector)
426
        set_offset (R_VRSAVE, &m->vrsave);
427
 
428
      /* Sometimes, srr0 points to the instruction that caused the exception,
429
         and sometimes to the next instruction to be executed; we want
430
         the latter.  */
431
      if (m->exception == 3 || m->exception == 4
432
          || m->exception == 6
433
          || (m->exception == 7 && !(m->srr1 & 0x10000)))
434
        return_addr = m->srr0 + 4;
435
      else
436
        return_addr = m->srr0;
437
    }
438
 
439
  fs->regs.cfa_how = CFA_REG_OFFSET;
440
  fs->regs.cfa_reg = STACK_POINTER_REGNUM;
441
  fs->regs.cfa_offset = new_cfa - old_cfa;;
442
 
443
  /* The choice of column for the return address is somewhat tricky.
444
     Fortunately, the actual choice is private to this file, and
445
     the space it's reserved from is the GCC register space, not the
446
     DWARF2 numbering.  So any free element of the right size is an OK
447
     choice.  Thus: */
448
  fs->retaddr_column = ARG_POINTER_REGNUM;
449
  /* FIXME: this should really be done using a DWARF2 location expression,
450
     not using a static variable.  In fact, this entire file should
451
     be implemented in DWARF2 expressions.  */
452
  set_offset (ARG_POINTER_REGNUM, &return_addr);
453
 
454
  for (i = 0; i < 32; i++)
455
    set_offset (32 + i, float_vector_state->fpregs + i);
456
  set_offset (R_SPEFSCR, &float_vector_state->fpscr);
457
 
458
  if (is_vector)
459
    {
460
      for (i = 0; i < 32; i++)
461
        set_offset (R_VR0 + i, float_vector_state->save_vr + i);
462
      set_offset (R_VSCR, float_vector_state->save_vscr);
463
    }
464
 
465
  return true;
466
}
467
 
468
/* This is also prototyped in rs6000/darwin.h, inside the
469
   MD_FALLBACK_FRAME_STATE_FOR macro.  */
470
extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
471
                                              _Unwind_FrameState *fs);
472
 
473
/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
474
   returning true iff the frame was a sigreturn() frame that we
475
   can understand.  */
476
 
477
bool
478
_Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
479
                                  _Unwind_FrameState *fs)
480
{
481
  reg_unit gprs[32];
482
 
483
  if (!interpret_libc (gprs, context))
484
    return false;
485
  return handle_syscall (fs, gprs, _Unwind_GetCFA (context));
486
}
487
#endif

powered by: WebSVN 2.1.0

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