OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [sparc/] [sol2-unwind.h] - Blame information for rev 378

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

Line No. Rev Author Line
1 282 jeremybenn
/* DWARF2 EH unwinding support for SPARC Solaris.
2
   Copyright (C) 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
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
 
30
#if defined(__arch64__)
31
 
32
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
33
 
34
static _Unwind_Reason_Code
35
sparc64_fallback_frame_state (struct _Unwind_Context *context,
36
                              _Unwind_FrameState *fs)
37
{
38
  void *pc = context->ra;
39
  void *this_cfa = context->cfa;
40
  void *new_cfa, *ra_location, *shifted_ra_location;
41
  int regs_off;
42
  int fpu_save_off;
43
  unsigned char fpu_save;
44
  int i;
45
 
46
  /* This is the observed pattern for the sigacthandler in Solaris 8.  */
47
  unsigned int sigacthandler_sol8_pattern []
48
    = {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003,
49
       0xe0590005, 0x9fc40000, 0x9410001a, 0x80a6e008};
50
 
51
  /* This is the observed pattern for the sigacthandler in Solaris 9.  */
52
  unsigned int sigacthandler_sol9_pattern []
53
    = {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011,
54
       0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008};
55
 
56
  /* This is the observed pattern for the __sighndlr.  */
57
  unsigned int sighndlr_pattern []
58
    = {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000,
59
       0x9410001a, 0x81c7e008, 0x81e80000};
60
 
61
  /* Deal with frame-less function from which a signal was raised.  */
62
  if (_Unwind_IsSignalFrame (context))
63
    {
64
      /* The CFA is by definition unmodified in this case.  */
65
      fs->regs.cfa_how = CFA_REG_OFFSET;
66
      fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
67
      fs->regs.cfa_offset = 0;
68
 
69
      /* This is the canonical RA column.  */
70
      fs->retaddr_column = 15;
71
 
72
      return _URC_NO_REASON;
73
    }
74
 
75
  /* Look for the sigacthandler pattern.  The pattern changes slightly
76
     in different versions of the operating system, so we skip the
77
     comparison against pc-(4*6) for Solaris 9.  */
78
  if ((    *(unsigned int *)(pc-(4*7)) == sigacthandler_sol8_pattern[0]
79
        && *(unsigned int *)(pc-(4*6)) == sigacthandler_sol8_pattern[1]
80
        && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol8_pattern[2]
81
        && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol8_pattern[3]
82
        && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol8_pattern[4]
83
        && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol8_pattern[5]
84
        && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol8_pattern[6]
85
        && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol8_pattern[7] ) ||
86
      (    *(unsigned int *)(pc-(4*7)) == sigacthandler_sol9_pattern[0]
87
        /* skip pc-(4*6) */
88
        && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol9_pattern[2]
89
        && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol9_pattern[3]
90
        && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol9_pattern[4]
91
        && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol9_pattern[5]
92
        && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol9_pattern[6]
93
        && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol9_pattern[7] ) )
94
    /* We need to move up two frames (the kernel frame and the handler
95
       frame).  Minimum stack frame size is 176 bytes (128 + 48): 128
96
       bytes for spilling register window (16 extended words for in
97
       and local registers), and 6 extended words to store at least
98
       6 arguments to callees, The kernel frame and the sigacthandler
99
       both have this minimal stack.  The ucontext_t structure is after
100
       this offset.  */
101
    regs_off = 176 + 176;
102
 
103
  /* Look for the __sighndlr pattern.  */
104
  else if (    *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
105
            && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
106
            && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
107
            && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
108
            && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
109
            && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
110
            && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
111
    {
112
      /* We have observed different calling frames among different
113
         versions of the operating system, so that we need to
114
         discriminate using the upper frame.  We look for the return
115
         address of the caller frame (there is an offset of 15 double
116
         words between the frame address and the place where this return
117
         address is stored) in order to do some more pattern matching.  */
118
      unsigned int cuh_pattern
119
        = *(unsigned int *)(*(unsigned long *)(this_cfa + 15*8) - 4);
120
 
121
      if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013)
122
        /* This matches the call_user_handler pattern for Solaris 9 and
123
           for Solaris 8 running inside Solaris Containers respectively.
124
           We need to move up four frames (the kernel frame, the signal
125
           frame, the call_user_handler frame, the __sighndlr frame).
126
           Three of them have the minimum stack frame size (kernel,
127
           signal, and __sighndlr frames) of 176 bytes, and there is
128
           another with a stack frame of 304 bytes (the call_user_handler
129
           frame).  The ucontext_t structure is after this offset.  */
130
        regs_off = 176 + 176 + 176 + 304;
131
      else
132
        /* We need to move up three frames (the kernel frame, the
133
           sigacthandler frame, and the __sighndlr frame).  The kernel
134
           frame has a stack frame size of 176, the __sighndlr frames of
135
           304 bytes, and there is a stack frame of 176 bytes for the
136
           sigacthandler frame.  The ucontext_t structure is after this
137
           offset.  */
138
        regs_off = 176 + 304 + 176;
139
    }
140
 
141
  /* Exit if the pattern at the return address does not match the
142
     previous three patterns.  */
143
  else
144
    return _URC_END_OF_STACK;
145
 
146
  /* FPU information can be extracted from the ucontext_t structure
147
     that is the third argument for the signal handler, that is saved
148
     in the stack.  There are 64 bytes between the beginning of the
149
     ucontext_t argument of the signal handler and the uc_mcontext
150
     field.  There are 176 bytes between the beginning of uc_mcontext
151
     and the beginning of the fpregs field.  */
152
  fpu_save_off = regs_off + (8*10) + 176;
153
 
154
  /* The fpregs field contains 32 extended words at the beginning that
155
     contain the fpu state.  Then there are 2 extended words and two
156
     bytes.  */
157
  fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (8*32) + (2*8) + 2);
158
 
159
  /* We need to get the frame pointer for the kernel frame that
160
     executes when the signal is raised.  This frame is just the
161
     following to the application code that generated the signal, so
162
     that the later's stack pointer is the former's frame pointer.
163
     The stack pointer for the interrupted application code can be
164
     calculated from the ucontext_t structure (third argument for the
165
     signal handler) that is saved in the stack.  There are 10 words
166
     between the beginning of the  ucontext_t argument  of the signal
167
     handler and the uc_mcontext.gregs field that contains the
168
     registers saved by the signal handler.  */
169
  new_cfa = *(void **)(this_cfa + regs_off + (8*10) + (REG_SP*8));
170
  /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
171
  new_cfa += 2047;
172
  fs->regs.cfa_how = CFA_REG_OFFSET;
173
  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
174
  fs->regs.cfa_offset = new_cfa - this_cfa;
175
 
176
  /* Restore global and out registers (in this order) from the
177
     ucontext_t structure, uc_mcontext.gregs field.  */
178
  for (i = 1; i < 16; i++)
179
    {
180
      /* We never restore %sp as everything is purely CFA-based.  */
181
      if ((unsigned int) i == __builtin_dwarf_sp_column ())
182
        continue;
183
 
184
      /* First the global registers and then the out registers.  */
185
      fs->regs.reg[i].how = REG_SAVED_OFFSET;
186
      fs->regs.reg[i].loc.offset
187
        = this_cfa + regs_off + (8*10) + ((REG_Y+i)*8) - new_cfa;
188
    }
189
 
190
  /* Just above the stack pointer there are 16 extended words in which
191
     the register window (in and local registers) was saved.  */
192
  for (i = 0; i < 16; i++)
193
    {
194
      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
195
      fs->regs.reg[i + 16].loc.offset = i*8;
196
    }
197
 
198
  /* Check whether we need to restore fpu registers.  */
199
  if (fpu_save)
200
    {
201
      for (i = 0; i < 64; i++)
202
        {
203
          if (i > 32 && (i & 1))
204
            continue;
205
 
206
          fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
207
          fs->regs.reg[i + 32].loc.offset
208
            = this_cfa + fpu_save_off + (i*4) - new_cfa;
209
        }
210
    }
211
 
212
  /* State the rules to find the kernel's code "return address", which is
213
     the address of the active instruction when the signal was caught.
214
     On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
215
     need to preventively subtract it from the purported return address.  */
216
  ra_location = this_cfa + regs_off + (8*10) + (REG_PC*8);
217
  shifted_ra_location = this_cfa + regs_off + (8*10) + (REG_Y*8);
218
  *(void **)shifted_ra_location = *(void **)ra_location - 8;
219
  fs->retaddr_column = 0;
220
  fs->regs.reg[0].how = REG_SAVED_OFFSET;
221
  fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
222
  fs->signal_frame = 1;
223
 
224
  return _URC_NO_REASON;
225
}
226
 
227
#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
228
 
229
static void
230
sparc64_frob_update_context (struct _Unwind_Context *context,
231
                             _Unwind_FrameState *fs)
232
{
233
  /* The column of %sp contains the old CFA, not the old value of %sp.
234
     The CFA offset already comprises the stack bias so, when %sp is the
235
     CFA register, we must avoid counting the stack bias twice.  Do not
236
     do that for signal frames as the offset is artificial for them.  */
237
  if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
238
      && fs->regs.cfa_how == CFA_REG_OFFSET
239
      && fs->regs.cfa_offset != 0
240
      && !fs->signal_frame)
241
    context->cfa -= 2047;
242
}
243
 
244
#else
245
 
246
#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
247
 
248
static _Unwind_Reason_Code
249
sparc_fallback_frame_state (struct _Unwind_Context *context,
250
                            _Unwind_FrameState *fs)
251
{
252
  void *pc = context->ra;
253
  void *this_cfa = context->cfa;
254
  void *new_cfa, *ra_location, *shifted_ra_location;
255
  int regs_off;
256
  int fpu_save_off;
257
  unsigned char fpu_save;
258
  int i;
259
 
260
  /* This is the observed pattern for the sigacthandler.  */
261
  unsigned int sigacthandler_pattern []
262
    = {0x9602400f, 0x92100019, 0x00000000, 0x912e2002,
263
       0xe002000a, 0x90100018, 0x9fc40000, 0x9410001a,
264
       0x80a62008};
265
 
266
  /* This is the observed pattern for the __libthread_segvhdlr.  */
267
  unsigned int segvhdlr_pattern []
268
    = {0x94102000, 0xe007bfe4, 0x9010001c, 0x92100019,
269
       0x9fc40000, 0x9410001a, 0x81c7e008, 0x81e80000,
270
       0x80a26000};
271
 
272
  /* This is the observed pattern for the __sighndlr.  */
273
  unsigned int sighndlr_pattern []
274
    = {0x9de3bfa0, 0x90100018, 0x92100019, 0x9fc6c000,
275
       0x9410001a, 0x81c7e008, 0x81e80000};
276
 
277
  /* Deal with frame-less function from which a signal was raised.  */
278
  if (_Unwind_IsSignalFrame (context))
279
    {
280
      /* The CFA is by definition unmodified in this case.  */
281
      fs->regs.cfa_how = CFA_REG_OFFSET;
282
      fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
283
      fs->regs.cfa_offset = 0;
284
 
285
      /* This is the canonical RA column.  */
286
      fs->retaddr_column = 15;
287
 
288
      return _URC_NO_REASON;
289
    }
290
 
291
  /* Look for the sigacthandler pattern.  The pattern changes slightly
292
     in different versions of the operating system, so we skip the
293
     comparison against pc-(4*6).  */
294
  if (    *(unsigned int *)(pc-(4*8)) == sigacthandler_pattern[0]
295
       && *(unsigned int *)(pc-(4*7)) == sigacthandler_pattern[1]
296
       /* skip pc-(4*6) */
297
       && *(unsigned int *)(pc-(4*5)) == sigacthandler_pattern[3]
298
       && *(unsigned int *)(pc-(4*4)) == sigacthandler_pattern[4]
299
       && *(unsigned int *)(pc-(4*3)) == sigacthandler_pattern[5]
300
       && *(unsigned int *)(pc-(4*2)) == sigacthandler_pattern[6]
301
       && *(unsigned int *)(pc-(4*1)) == sigacthandler_pattern[7]
302
       && *(unsigned int *)(pc-(4*0)) == sigacthandler_pattern[8] )
303
    /* We need to move up two frames (the kernel frame and the handler
304
       frame).  Minimum stack frame size is 96 bytes (64 + 4 + 24): 64
305
       bytes for spilling register window (16 words for in and local
306
       registers), 4 bytes for a pointer to space for callees
307
       returning structs, and 24 bytes to store at least six argument
308
       to callees.  The ucontext_t structure is after this offset.  */
309
    regs_off = 96 + 96;
310
 
311
  /* Look for the __libthread_segvhdlr pattern.  */
312
  else if (    *(unsigned int *)(pc-(4*6)) == segvhdlr_pattern[0]
313
            && *(unsigned int *)(pc-(4*5)) == segvhdlr_pattern[1]
314
            && *(unsigned int *)(pc-(4*4)) == segvhdlr_pattern[2]
315
            && *(unsigned int *)(pc-(4*3)) == segvhdlr_pattern[3]
316
            && *(unsigned int *)(pc-(4*2)) == segvhdlr_pattern[4]
317
            && *(unsigned int *)(pc-(4*1)) == segvhdlr_pattern[5]
318
            && *(unsigned int *)(pc-(4*0)) == segvhdlr_pattern[6]
319
            && *(unsigned int *)(pc+(4*1)) == segvhdlr_pattern[7]
320
            && *(unsigned int *)(pc+(4*2)) == segvhdlr_pattern[8] )
321
    /* We need to move up four frames (the kernel frame, the
322
       sigacthandler frame, the __sighndlr frame, and the
323
       __libthread_segvhdlr).  Two of them have the minimum
324
       stack frame size (kernel and __sighndlr frames) of 96 bytes,
325
       other has a stack frame of 216 bytes (the sigacthandler frame),
326
       and there is another with a stack frame of 128 bytes (the
327
       __libthread_segvhdlr).  The ucontext_t structure is after this
328
       offset.  */
329
    regs_off = 96 + 96 + 128 + 216;
330
 
331
  /* Look for the __sighndlr pattern.  */
332
  else if (    *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
333
            && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
334
            && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
335
            && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
336
            && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
337
            && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
338
            && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
339
    {
340
      /* We have observed different calling frames among different
341
         versions of the operating system, so that we need to
342
         discriminate using the upper frame.  We look for the return
343
         address of the caller frame (there is an offset of 15 words
344
         between the frame address and the place where this return
345
         address is stored) in order to do some more pattern matching.  */
346
      unsigned int cuh_pattern
347
        = *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4);
348
 
349
      if (cuh_pattern == 0xd407a04c)
350
        /* This matches the call_user_handler pattern for Solaris 10.
351
           We need to move up three frames (the kernel frame, the
352
           call_user_handler frame, the __sighndlr frame).  Two of them
353
           have the minimum stack frame size (kernel and __sighndlr
354
           frames) of 96 bytes, and there is another with a stack frame
355
           of 160 bytes (the call_user_handler frame).  The ucontext_t
356
          structure is after this offset.  */
357
        regs_off = 96 + 96 + 160;
358
      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
359
        /* This matches the call_user_handler pattern for Solaris 9 and
360
           for Solaris 8 running inside Solaris Containers respectively.
361
           We need to move up four frames (the kernel frame, the signal
362
           frame, the call_user_handler frame, the __sighndlr frame).
363
           Three of them have the minimum stack frame size (kernel,
364
           signal, and __sighndlr frames) of 96 bytes, and there is
365
           another with a stack frame of 160 bytes (the call_user_handler
366
           frame).  The ucontext_t structure is after this offset.  */
367
        regs_off = 96 + 96 + 96 + 160;
368
      else
369
        /* We need to move up three frames (the kernel frame, the
370
           sigacthandler frame, and the __sighndlr frame).  Two of them
371
           have the minimum stack frame size (kernel and __sighndlr
372
           frames) of 96 bytes, and there is another with a stack frame
373
           of 216 bytes (the sigacthandler frame).  The ucontext_t
374
           structure is after this offset.  */
375
        regs_off = 96 + 96 + 216;
376
    }
377
 
378
  /* Exit if the pattern at the return address does not match the
379
     previous three patterns.  */
380
  else
381
    return _URC_END_OF_STACK;
382
 
383
  /* FPU information can be extracted from the ucontext_t structure
384
     that is the third argument for the signal handler, that is saved
385
     in the stack.  There are 10 words between the beginning of the
386
     ucontext_t argument of the signal handler and the uc_mcontext
387
     field.  There are 80 bytes between the beginning of uc_mcontext
388
     and the beginning of the fpregs field.  */
389
  fpu_save_off = regs_off + (4*10) + (4*20);
390
 
391
  /* The fpregs field contains 32 words at the beginning that contain
392
     the fpu state.  Then there are 2 words and two bytes.  */
393
  fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (4*32) + (2*4) + 2);
394
 
395
  /* We need to get the frame pointer for the kernel frame that
396
     executes when the signal is raised.  This frame is just the
397
     following to the application code that generated the signal, so
398
     that the later's stack pointer is the former's frame pointer.
399
     The stack pointer for the interrupted application code can be
400
     calculated from the ucontext_t structure (third argument for the
401
     signal handler) that is saved in the stack.  There are 10 words
402
     between the beginning of the  ucontext_t argument  of the signal
403
     handler and the uc_mcontext.gregs field that contains the
404
     registers saved by the signal handler.  */
405
  new_cfa = *(void **)(this_cfa + regs_off + (4*10) + (REG_SP*4));
406
  fs->regs.cfa_how = CFA_REG_OFFSET;
407
  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
408
  fs->regs.cfa_offset = new_cfa - this_cfa;
409
 
410
  /* Restore global and out registers (in this order) from the
411
     ucontext_t structure, uc_mcontext.gregs field.  */
412
  for (i = 1; i < 16; i++)
413
    {
414
      /* We never restore %sp as everything is purely CFA-based.  */
415
      if ((unsigned int) i == __builtin_dwarf_sp_column ())
416
        continue;
417
 
418
      /* First the global registers and then the out registers */
419
      fs->regs.reg[i].how = REG_SAVED_OFFSET;
420
      fs->regs.reg[i].loc.offset
421
        = this_cfa + regs_off + (4*10) + ((REG_Y+i)*4) - new_cfa;
422
    }
423
 
424
  /* Just above the stack pointer there are 16 words in which the
425
     register window (in and local registers) was saved.  */
426
  for (i = 0; i < 16; i++)
427
    {
428
      fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
429
      fs->regs.reg[i + 16].loc.offset = i*4;
430
    }
431
 
432
  /* Check whether we need to restore fpu registers.  */
433
  if (fpu_save)
434
    {
435
      for (i = 0; i < 32; i++)
436
        {
437
          fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
438
          fs->regs.reg[i + 32].loc.offset
439
            = this_cfa + fpu_save_off + (i*4) - new_cfa;
440
        }
441
    }
442
 
443
  /* State the rules to find the kernel's code "return address", which is
444
     the address of the active instruction when the signal was caught.
445
     On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
446
     need to preventively subtract it from the purported return address.  */
447
  ra_location = this_cfa + regs_off + (4*10) + (REG_PC*4);
448
  shifted_ra_location = this_cfa + regs_off + (4*10) + (REG_Y*4);
449
  *(void **)shifted_ra_location = *(void **)ra_location - 8;
450
  fs->retaddr_column = 0;
451
  fs->regs.reg[0].how = REG_SAVED_OFFSET;
452
  fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
453
  fs->signal_frame = 1;
454
 
455
  return _URC_NO_REASON;
456
};
457
 
458
#endif

powered by: WebSVN 2.1.0

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