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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [rs6000/] [darwin-fallback.c] - Blame information for rev 825

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

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

powered by: WebSVN 2.1.0

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