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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [rs6000/] [darwin-fallback.c] - Blame information for rev 734

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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