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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [sparc/] [sol2-unwind.h] - Blame information for rev 734

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 734 jeremybenn
/* DWARF2 EH unwinding support for SPARC Solaris.
2
   Copyright (C) 2009, 2010, 2011, 2012 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
7
it 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,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public 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
/* Do code reading to identify a signal frame, and set the frame
26
   state data appropriately.  See unwind-dw2.c for the structs.  */
27
 
28
#include <ucontext.h>
29
#include <sys/frame.h>
30
#include <sys/stack.h>
31
 
32
#ifdef __arch64__
33
 
34
#define IS_SIGHANDLER sparc64_is_sighandler
35
 
36
static int
37
sparc64_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
38
{
39
  if (/* Solaris 8 - single-threaded
40
        ----------------------------
41
        <sigacthandler+24>:  add  %g5, %o7, %o2
42
        <sigacthandler+28>:  ldx  [ %o2 + 0xfa0 ], %g5
43
        <sigacthandler+32>:  sra  %i0, 0, %o0
44
        <sigacthandler+36>:  sllx  %o0, 3, %g4
45
        <sigacthandler+40>:  ldx  [ %g4 + %g5 ], %l0
46
        <sigacthandler+44>:  call  %l0
47
        <sigacthandler+48>:  mov  %i2, %o2
48
        <sigacthandler+52>:  cmp  %i3, 8        <--- PC  */
49
      (   pc[-7] == 0x9401400f
50
       && pc[-6] == 0xca5aafa0
51
       && pc[-5] == 0x913e2000
52
       && pc[-4] == 0x892a3003
53
       && pc[-3] == 0xe0590005
54
       && pc[-2] == 0x9fc40000
55
       && pc[-1] == 0x9410001a
56
       && pc[ 0] == 0x80a6e008)
57
 
58
      || /* Solaris 9 - single-threaded
59
           ----------------------------
60
           The pattern changes slightly in different versions of the
61
           operating system, so we skip the comparison against pc[-6] for
62
           Solaris 9.
63
 
64
           <sigacthandler+24>:  sra  %i0, 0, %l1
65
 
66
           Solaris 9 5/02:
67
           <sigacthandler+28>:  ldx  [ %o2 + 0xf68 ], %g5
68
           Solaris 9 9/05:
69
           <sigacthandler+28>:  ldx  [ %o2 + 0xe50 ], %g5
70
 
71
           <sigacthandler+32>:  sllx  %l1, 3, %g4
72
           <sigacthandler+36>:  mov  %l1, %o0
73
           <sigacthandler+40>:  ldx  [ %g4 + %g5 ], %l0
74
           <sigacthandler+44>:  call  %l0
75
           <sigacthandler+48>:  mov  %i2, %o2
76
           <sigacthandler+52>:  cmp  %l1, 8     <--- PC  */
77
      (   pc[-7] == 0xa33e2000
78
       /* skip pc[-6] */
79
       && pc[-5] == 0x892c7003
80
       && pc[-4] == 0x90100011
81
       && pc[-3] == 0xe0590005
82
       && pc[-2] == 0x9fc40000
83
       && pc[-1] == 0x9410001a
84
       && pc[ 0] == 0x80a46008))
85
    {
86
      /* We need to move up one frame:
87
 
88
                <signal handler>        <-- context->cfa
89
                sigacthandler
90
                <kernel>
91
      */
92
      *nframes = 1;
93
      return 1;
94
    }
95
 
96
  if (/* Solaris 8+ - multi-threaded
97
        ----------------------------
98
        <__sighndlr>:        save  %sp, -176, %sp
99
        <__sighndlr+4>:      mov  %i0, %o0
100
        <__sighndlr+8>:      mov  %i1, %o1
101
        <__sighndlr+12>:     call  %i3
102
        <__sighndlr+16>:     mov  %i2, %o2
103
        <__sighndlr+20>:     ret                <--- PC
104
        <__sighndlr+24>:     restore  */
105
         pc[-5] == 0x9de3bf50
106
      && pc[-4] == 0x90100018
107
      && pc[-3] == 0x92100019
108
      && pc[-2] == 0x9fc6c000
109
      && pc[-1] == 0x9410001a
110
      && pc[ 0] == 0x81c7e008
111
      && pc[ 1] == 0x81e80000)
112
    {
113
      /* We have observed different calling frames among different
114
         versions of the operating system, so that we need to
115
         discriminate using the upper frame.  We look for the return
116
         address of the caller frame (there is an offset of 15 double
117
         words between the frame address and the place where this return
118
         address is stored) in order to do some more pattern matching.  */
119
      unsigned int cuh_pattern
120
        = *(unsigned int *)(*(unsigned long *)(cfa + 15*8) - 4);
121
 
122
      if (cuh_pattern == 0x92100019)
123
        /* This matches the call_user_handler pattern for Solaris 11.
124
           This is the same setup as for Solaris 9, see below.  */
125
        *nframes = 3;
126
 
127
      else if (cuh_pattern == 0xd25fa7ef)
128
        {
129
          /* This matches the call_user_handler pattern for Solaris 10.
130
             There are 2 cases so we look for the return address of the
131
             caller's caller frame in order to do more pattern matching.  */
132
          unsigned long sah_address = *(unsigned long *)(cfa + 176 + 15*8);
133
 
134
          if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
135
            /* This is the same setup as for Solaris 9, see below.  */
136
            *nframes = 3;
137
          else
138
            /* The sigacthandler frame isn't present in the chain.
139
               We need to move up two frames:
140
 
141
                <signal handler>        <-- context->cfa
142
                __sighndlr
143
                call_user_handler frame
144
                <kernel>
145
            */
146
            *nframes = 2;
147
        }
148
 
149
      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
150
        /* This matches the call_user_handler pattern for Solaris 9 and
151
           for Solaris 8 running inside Solaris Containers respectively
152
           We need to move up three frames:
153
 
154
                <signal handler>        <-- context->cfa
155
                __sighndlr
156
                call_user_handler
157
                sigacthandler
158
                <kernel>
159
        */
160
        *nframes = 3;
161
 
162
      else /* cuh_pattern == 0xe0272010 */
163
        /* This is the default Solaris 8 case.
164
           We need to move up two frames:
165
 
166
                <signal handler>        <-- context->cfa
167
                __sighndlr
168
                sigacthandler
169
                <kernel>
170
        */
171
        *nframes = 2;
172
 
173
      return 1;
174
    }
175
 
176
  return 0;
177
}
178
 
179
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
180
 
181
#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
182
 
183
static void
184
sparc64_frob_update_context (struct _Unwind_Context *context,
185
                             _Unwind_FrameState *fs)
186
{
187
  /* The column of %sp contains the old CFA, not the old value of %sp.
188
     The CFA offset already comprises the stack bias so, when %sp is the
189
     CFA register, we must avoid counting the stack bias twice.  Do not
190
     do that for signal frames as the offset is artificial for them.  */
191
  if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
192
      && fs->regs.cfa_how == CFA_REG_OFFSET
193
      && fs->regs.cfa_offset != 0
194
      && !fs->signal_frame)
195
    {
196
      long i;
197
 
198
      context->cfa -= STACK_BIAS;
199
 
200
      for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
201
        if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
202
          _Unwind_SetGRPtr (context, i,
203
                            _Unwind_GetGRPtr (context, i) - STACK_BIAS);
204
    }
205
}
206
 
207
#else
208
 
209
#define IS_SIGHANDLER sparc_is_sighandler
210
 
211
static int
212
sparc_is_sighandler (unsigned int *pc, void *cfa, int *nframes)
213
{
214
  if (/* Solaris 8, 9 - single-threaded
215
        -------------------------------
216
        The pattern changes slightly in different versions of the operating
217
        system, so we skip the comparison against pc[-6].
218
 
219
        <sigacthandler+16>:  add  %o1, %o7, %o3
220
        <sigacthandler+20>:  mov  %i1, %o1
221
 
222
        <sigacthandler+24>:  ld  [ %o3 + <offset> ], %o2
223
 
224
        <sigacthandler+28>:  sll  %i0, 2, %o0
225
        <sigacthandler+32>:  ld  [ %o0 + %o2 ], %l0
226
        <sigacthandler+36>:  mov  %i0, %o0
227
        <sigacthandler+40>:  call  %l0
228
        <sigacthandler+44>:  mov  %i2, %o2
229
        <sigacthandler+48>:  cmp  %i0, 8        <--- PC  */
230
         pc[-8] == 0x9602400f
231
      && pc[-7] == 0x92100019
232
      /* skip pc[-6] */
233
      && pc[-5] == 0x912e2002
234
      && pc[-4] == 0xe002000a
235
      && pc[-3] == 0x90100018
236
      && pc[-2] == 0x9fc40000
237
      && pc[-1] == 0x9410001a
238
      && pc[ 0] == 0x80a62008)
239
    {
240
      /* We need to move up one frame:
241
 
242
                <signal handler>        <-- context->cfa
243
                sigacthandler
244
                <kernel>
245
      */
246
      *nframes = 1;
247
      return 1;
248
    }
249
 
250
  if (/* Solaris 8 - multi-threaded
251
        ---------------------------
252
        <__libthread_segvhdlr+212>:  clr  %o2
253
        <__libthread_segvhdlr+216>:  ld  [ %fp + -28 ], %l0
254
        <__libthread_segvhdlr+220>:  mov  %i4, %o0
255
        <__libthread_segvhdlr+224>:  mov  %i1, %o1
256
        <__libthread_segvhdlr+228>:  call  %l0
257
        <__libthread_segvhdlr+232>:  mov  %i2, %o2
258
        <__libthread_segvhdlr+236>:  ret                <--- PC
259
        <__libthread_segvhdlr+240>:  restore
260
        <__libthread_segvhdlr+244>:  cmp  %o1, 0  */
261
         pc[-6] == 0x94102000
262
      && pc[-5] == 0xe007bfe4
263
      && pc[-4] == 0x9010001c
264
      && pc[-3] == 0x92100019
265
      && pc[-2] == 0x9fc40000
266
      && pc[-1] == 0x9410001a
267
      && pc[ 0] == 0x81c7e008
268
      && pc[ 1] == 0x81e80000
269
      && pc[ 2] == 0x80a26000)
270
    {
271
      /* We need to move up one frame:
272
 
273
                <signal handler>        <-- context->cfa
274
                __libthread_segvhdlr
275
                <kernel>
276
      */
277
      *nframes = 1;
278
      return 1;
279
    }
280
 
281
  if(/* Solaris 8+ - multi-threaded
282
       ----------------------------
283
       <__sighndlr>:    save  %sp, -96, %sp
284
       <__sighndlr+4>:  mov  %i0, %o0
285
       <__sighndlr+8>:  mov  %i1, %o1
286
       <__sighndlr+12>: call  %i3
287
       <__sighndlr+16>: mov  %i2, %o2
288
       <__sighndlr+20>: ret             <--- PC
289
       <__sighndlr+24>: restore  */
290
        pc[-5] == 0x9de3bfa0
291
     && pc[-4] == 0x90100018
292
     && pc[-3] == 0x92100019
293
     && pc[-2] == 0x9fc6c000
294
     && pc[-1] == 0x9410001a
295
     && pc[ 0] == 0x81c7e008
296
     && pc[ 1] == 0x81e80000)
297
    {
298
      /* We have observed different calling frames among different
299
         versions of the operating system, so that we need to
300
         discriminate using the upper frame.  We look for the return
301
         address of the caller frame (there is an offset of 15 words
302
         between the frame address and the place where this return
303
         address is stored) in order to do some more pattern matching.  */
304
      unsigned int cuh_pattern
305
        = *(unsigned int *)(*(unsigned int *)(cfa + 15*4) - 4);
306
 
307
      if (cuh_pattern == 0x92100019)
308
        /* This matches the call_user_handler pattern for Solaris 11.
309
           This is the same setup as for Solaris 9, see below.  */
310
        *nframes = 3;
311
 
312
      else if (cuh_pattern == 0xd407a04c)
313
        {
314
          /* This matches the call_user_handler pattern for Solaris 10.
315
             There are 2 cases so we look for the return address of the
316
             caller's caller frame in order to do more pattern matching.  */
317
          unsigned int sah_address = *(unsigned int *)(cfa + 96 + 15*4);
318
 
319
          if (sah_address && *(unsigned int *)(sah_address - 4) == 0x92100019)
320
            /* This is the same setup as for Solaris 9, see below.  */
321
            *nframes = 3;
322
          else
323
            /* The sigacthandler frame isn't present in the chain.
324
               We need to move up two frames:
325
 
326
                <signal handler>        <-- context->cfa
327
                __sighndlr
328
                call_user_handler frame
329
                <kernel>
330
            */
331
            *nframes = 2;
332
        }
333
 
334
      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
335
        /* This matches the call_user_handler pattern for Solaris 9 and
336
           for Solaris 8 running inside Solaris Containers respectively.
337
           We need to move up three frames:
338
 
339
                <signal handler>        <-- context->cfa
340
                __sighndlr
341
                call_user_handler
342
                sigacthandler
343
                <kernel>
344
        */
345
        *nframes = 3;
346
 
347
      else /* cuh_pattern == 0x90100018 */
348
        /* This is the default Solaris 8 case.
349
           We need to move up two frames:
350
 
351
                <signal handler>        <-- context->cfa
352
                __sighndlr
353
                sigacthandler
354
                <kernel>
355
        */
356
        *nframes = 2;
357
 
358
      return 1;
359
    }
360
 
361
  return 0;
362
}
363
 
364
#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
365
 
366
#endif
367
 
368
static _Unwind_Reason_Code
369
MD_FALLBACK_FRAME_STATE_FOR (struct _Unwind_Context *context,
370
                             _Unwind_FrameState *fs)
371
{
372
  void *pc = context->ra;
373
  struct frame *fp = (struct frame *) context->cfa;
374
  int nframes;
375
  void *this_cfa = context->cfa;
376
  long new_cfa;
377
  void *ra_location, *shifted_ra_location;
378
  mcontext_t *mctx;
379
  int i;
380
 
381
  /* Deal with frame-less function from which a signal was raised.  */
382
  if (_Unwind_IsSignalFrame (context))
383
    {
384
      /* The CFA is by definition unmodified in this case.  */
385
      fs->regs.cfa_how = CFA_REG_OFFSET;
386
      fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
387
      fs->regs.cfa_offset = 0;
388
 
389
      /* This is the canonical RA column.  */
390
      fs->retaddr_column = 15;
391
 
392
      return _URC_NO_REASON;
393
    }
394
 
395
  if (IS_SIGHANDLER (pc, this_cfa, &nframes))
396
    {
397
      struct handler_args {
398
        struct frame frwin;
399
        ucontext_t ucontext;
400
      } *handler_args;
401
      ucontext_t *ucp;
402
 
403
      /* context->cfa points into the frame after the saved frame pointer and
404
         saved pc (struct frame).
405
 
406
         The ucontext_t structure is in the kernel frame after a struct
407
         frame.  Since the frame sizes vary even within OS releases, we
408
         need to walk the stack to get there.  */
409
 
410
      for (i = 0; i < nframes; i++)
411
        fp = (struct frame *) ((char *)fp->fr_savfp + STACK_BIAS);
412
 
413
      handler_args = (struct handler_args *) fp;
414
      ucp = &handler_args->ucontext;
415
      mctx = &ucp->uc_mcontext;
416
    }
417
 
418
  /* Exit if the pattern at the return address does not match the
419
     previous three patterns.  */
420
  else
421
    return _URC_END_OF_STACK;
422
 
423
  new_cfa = mctx->gregs[REG_SP];
424
  /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
425
  new_cfa += STACK_BIAS;
426
 
427
  fs->regs.cfa_how = CFA_REG_OFFSET;
428
  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
429
  fs->regs.cfa_offset = new_cfa - (long) this_cfa;
430
 
431
  /* Restore global and out registers (in this order) from the
432
     ucontext_t structure, uc_mcontext.gregs field.  */
433
  for (i = 1; i < 16; i++)
434
    {
435
      /* We never restore %sp as everything is purely CFA-based.  */
436
      if ((unsigned int) i == __builtin_dwarf_sp_column ())
437
        continue;
438
 
439
      /* First the global registers and then the out registers.  */
440
      fs->regs.reg[i].how = REG_SAVED_OFFSET;
441
      fs->regs.reg[i].loc.offset = (long)&mctx->gregs[REG_Y + i] - new_cfa;
442
    }
443
 
444
  /* Just above the stack pointer there are 16 extended words in which
445
     the register window (in and local registers) was saved.  */
446
  for (i = 0; i < 16; i++)
447
    {
448
      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
449
      fs->regs.reg[i + 16].loc.offset = i*sizeof(long);
450
    }
451
 
452
  /* Check whether we need to restore FPU registers.  */
453
  if (mctx->fpregs.fpu_qcnt)
454
    {
455
      for (i = 0; i < 32; i++)
456
        {
457
          fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
458
          fs->regs.reg[i + 32].loc.offset
459
            = (long)&mctx->fpregs.fpu_fr.fpu_regs[i] - new_cfa;
460
        }
461
 
462
#ifdef __arch64__
463
      /* For 64-bit, fpu_fr.fpu_dregs contains 32 instead of 16 doubles.  */
464
      for (i = 32; i < 64; i++)
465
        {
466
          if (i > 32 && (i & 1))
467
            continue;
468
 
469
          fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
470
          fs->regs.reg[i + 32].loc.offset
471
            = (long)&mctx->fpregs.fpu_fr.fpu_dregs[i/2] - new_cfa;
472
        }
473
#endif
474
    }
475
 
476
  /* State the rules to find the kernel's code "return address", which is
477
     the address of the active instruction when the signal was caught.
478
     On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
479
     need to preventively subtract it from the purported return address.  */
480
  ra_location = &mctx->gregs[REG_PC];
481
  shifted_ra_location = &mctx->gregs[REG_Y];
482
  *(void **)shifted_ra_location = *(void **)ra_location - 8;
483
  fs->retaddr_column = 0;
484
  fs->regs.reg[0].how = REG_SAVED_OFFSET;
485
  fs->regs.reg[0].loc.offset = (long)shifted_ra_location - new_cfa;
486
  fs->signal_frame = 1;
487
 
488
  return _URC_NO_REASON;
489
}

powered by: WebSVN 2.1.0

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