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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [alpha/] [osf5-unwind.h] - Blame information for rev 849

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

Line No. Rev Author Line
1 734 jeremybenn
/* DWARF2 EH unwinding support for Alpha Tru64.
2
   Copyright (C) 2010 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 under
7
the terms of the GNU General Public License as published by the Free
8
Software Foundation; either version 3, or (at your option) any later
9
version.
10
 
11
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12
WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GCC; see the file COPYING3.  If not see
18
<http://www.gnu.org/licenses/>.  */
19
 
20
/* This file implements the MD_FALLBACK_FRAME_STATE_FOR macro, triggered when
21
   the GCC table based unwinding process hits a frame for which no unwind info
22
   has been registered. This typically occurs when raising an exception from a
23
   signal handler, because the handler is actually called from the OS kernel.
24
 
25
   The basic idea is to detect that we are indeed trying to unwind past a
26
   signal handler and to fill out the GCC internal unwinding structures for
27
   the OS kernel frame as if it had been directly called from the interrupted
28
   context.
29
 
30
   This is all assuming that the code to set the handler asked the kernel to
31
   pass a pointer to such context information.  */
32
 
33
/* --------------------------------------------------------------------------
34
   -- Basic principles of operation:
35
   --------------------------------------------------------------------------
36
 
37
   1/ We first need a way to detect if we are trying to unwind past a signal
38
      handler.
39
 
40
   The typical method that is used on most platforms is to look at the code
41
   around the return address we have and check if it matches the OS code
42
   calling a handler.  To determine what this code is expected to be, get a
43
   breakpoint into a real signal handler and look at the code around the
44
   return address.  Depending on the library versions the pattern of the
45
   signal handler is different; this is the reason why we check against more
46
   than one pattern.
47
 
48
   On this target, the return address is right after the call and every
49
   instruction is 4 bytes long.  For the simple case of a null dereference in
50
   a single-threaded app, it went like:
51
 
52
   # Check that we indeed have something we expect: the instruction right
53
   # before the return address is within a __sigtramp function and is a call.
54
 
55
   [... run gdb and break at the signal handler entry ...]
56
 
57
   (gdb) x /i $ra-4
58
   <__sigtramp+160>: jsr     ra,(a3),0x3ff800d0ed4 <_fpdata+36468>
59
 
60
   # Look at the code around that return address, and eventually observe a
61
   # significantly large chunk of *constant* code right before the call:
62
 
63
   (gdb) x /10i  $ra-44
64
   <__sigtramp+120>: lda     gp,-27988(gp)
65
   <__sigtramp+124>: ldq     at,-18968(gp)
66
   <__sigtramp+128>: lda     t0,-1
67
   <__sigtramp+132>: stq     t0,0(at)
68
   <__sigtramp+136>: ldq     at,-18960(gp)
69
   <__sigtramp+140>: ldl     t1,8(at)
70
   <__sigtramp+144>: ldq     at,-18960(gp)
71
   <__sigtramp+148>: stl     t1,12(at)
72
   <__sigtramp+152>: ldq     at,-18960(gp)
73
   <__sigtramp+156>: stl     t0,8(at)
74
 
75
   # The hexadecimal equivalent that we will have to match is:
76
 
77
   (gdb) x /10x  $ra-44
78
   <__sigtramp+120>: 0x23bd92ac    0xa79db5e8    0x203fffff   0xb43c0000
79
   <__sigtramp+136>: 0xa79db5f0    0xa05c0008    0xa79db5f0   0xb05c000c
80
   <__sigtramp+152>: 0xa79db5f0    0xb03c0008
81
 
82
   The problem observed on this target with this approach is that although
83
   we found a constant set of instruction patterns there were some
84
   gp-related offsets that made the machine code to differ from one
85
   installation to another.  This problem could have been overcome by masking
86
   these offsets, but we found that it would be simpler and more efficient to
87
   check whether the return address was part of a signal handler, by comparing
88
   it against some expected code offset from __sigtramp.
89
 
90
   # Check that we indeed have something we expect: the instruction
91
   # right before the return address is within a __sigtramp
92
   # function and is a call. We also need to obtain the offset
93
   # between the return address and the start address of __sigtramp.
94
 
95
   [... run gdb and break at the signal handler entry ...]
96
 
97
   (gdb) x /2i $ra-4
98
   <__sigtramp+160>: jsr     ra,(a3),0x3ff800d0ed4 <_fpdata+36468>
99
   <__sigtramp+164>: ldah    gp,16381(ra)
100
 
101
   (gdb) p (long)$ra - (long)&__sigtramp
102
   $2 = 164
103
 
104
   --------------------------------------------------------------------------
105
 
106
   2/ Once we know we are going through a signal handler, we need a way to
107
      retrieve information about the interrupted run-time context.
108
 
109
   On this platform, the third handler's argument is a pointer to a structure
110
   describing this context (struct sigcontext *). We unfortunately have no
111
   direct way to transfer this value here, so a couple of tricks are required
112
   to compute it.
113
 
114
   As documented at least in some header files (e.g. sys/machine/context.h),
115
   the structure the handler gets a pointer to is located on the stack.  As of
116
   today, while writing this macro, we have unfortunately not been able to
117
   find a detailed description of the full stack layout at handler entry time,
118
   so we'll have to resort to empirism :)
119
 
120
   When unwinding here, we have the handler's CFA at hand, as part of the
121
   current unwinding context which is one of our arguments.  We presume that
122
   for each call to a signal handler by the same kernel routine, the context's
123
   structure location on the stack is always at the same offset from the
124
   handler's CFA, and we compute that offset from bare observation:
125
 
126
   For the simple case of a bare null dereference in a single-threaded app,
127
   computing the offset was done using GNAT like this:
128
 
129
   # Break on the first handler's instruction, before the prologue to have the
130
   # CFA in $sp, and get there:
131
 
132
   (gdb) b *&__gnat_error_handler
133
   Breakpoint 1 at 0x120016090: file init.c, line 378.
134
 
135
   (gdb) r
136
   Program received signal SIGSEGV, Segmentation fault.
137
 
138
   (gdb) c
139
   Breakpoint 1, __gnat_error_handler (sig=..., sip=..., context=...)
140
 
141
   # The displayed argument value are meaningless because we stopped before
142
   # their final "homing". We know they are passed through $a0, $a1 and $a2
143
   # from the ABI, though, so ...
144
 
145
   # Observe that $sp and the context pointer are in the same (stack) area,
146
   # and compute the offset:
147
 
148
   (gdb) p /x $sp
149
   $2 = 0x11fffbc80
150
 
151
   (gdb) p /x $a2
152
   $3 = 0x11fffbcf8
153
 
154
   (gdb) p /x (long)$a2 - (long)$sp
155
   $4 = 0x78
156
 
157
   --------------------------------------------------------------------------
158
 
159
   3/ Once we know we are unwinding through a signal handler and have the
160
      address of the structure describing the interrupted context at hand, we
161
      have to fill the internal frame-state/unwind-context structures properly
162
      to allow the unwinding process to proceed.
163
 
164
   Roughly, we are provided with an *unwinding* CONTEXT, describing the state
165
   of some point P in the call chain we are unwinding through.  The macro we
166
   implement has to fill a "frame state" structure FS that describe the P's
167
   caller state, by way of *rules* to compute its CFA, return address, and
168
   **saved** registers *locations*.
169
 
170
   For the case we are going to deal with, the caller is some kernel code
171
   calling a signal handler, and:
172
 
173
   o The saved registers are all in the interrupted run-time context,
174
 
175
   o The CFA is the stack pointer value when the kernel code is entered, that
176
     is, the stack pointer value at the interruption point, also part of the
177
     interrupted run-time context.
178
 
179
   o We want the return address to appear as the address of the active
180
     instruction at the interruption point, so that the unwinder proceeds as
181
     if the interruption had been a regular call.  This address is also part
182
     of the interrupted run-time context.
183
 
184
   --
185
 
186
   Also, note that there is an important difference between the return address
187
   we need to claim for the kernel frame and the value of the return address
188
   register at the interruption point.
189
 
190
   The latter might be required to be able to unwind past the interrupted
191
   routine, for instance if it is interrupted before saving the incoming
192
   register value in its own frame, which may typically happen during stack
193
   probes for stack-checking purposes.
194
 
195
   It is then essential that the rules stated to locate the kernel frame
196
   return address don't clobber the rules describing where is saved the return
197
   address register at the interruption point, so some scratch register state
198
   entry should be used for the former. We have DWARF_ALT_FRAME_RETURN_COLUMN
199
   at hand exactly for that purpose.
200
 
201
   --------------------------------------------------------------------------
202
 
203
   4/ Depending on the context (single-threaded or multi-threaded app, ...),
204
   the code calling the handler and the handler-cfa to interrupted-context
205
   offset might change, so we use a simple generic data structure to track
206
   the possible variants.  */
207
 
208
/* This is the structure to wrap information about each possible sighandler
209
   caller we may have to identify.  */
210
 
211
typedef struct {
212
  /* Expected return address when being called from a sighandler.  */
213
  void *ra_value;
214
 
215
  /* Offset to get to the sigcontext structure from the handler's CFA
216
     when the pattern matches.  */
217
  int cfa_to_context_offset;
218
 
219
} sighandler_call_t;
220
 
221
/* Helper macro for MD_FALLBACK_FRAME_STATE_FOR below.
222
 
223
   Look at RA to see if it matches within a sighandler caller.
224
   Set SIGCTX to the corresponding sigcontext structure (computed from
225
   CFA) if it does, or to 0 otherwise.  */
226
 
227
#define COMPUTE_SIGCONTEXT_FOR(RA,CFA,SIGCTX)                               \
228
do {                                                                        \
229
  /* Define and register the applicable patterns.  */                       \
230
  extern void __sigtramp (void);                                            \
231
                                                                            \
232
  sighandler_call_t sighandler_calls [] = {                                 \
233
    {__sigtramp + 164, 0x78}                                                \
234
  };                                                                        \
235
                                                                            \
236
  int n_patterns_to_match                                                   \
237
    = sizeof (sighandler_calls) / sizeof (sighandler_call_t);               \
238
                                                                            \
239
  int pn;  /* pattern number  */                                            \
240
                                                                            \
241
  int match = 0;  /* Did last pattern match ?  */                            \
242
                                                                            \
243
  /* Try to match each pattern in turn.  */                                 \
244
  for (pn = 0; !match && pn < n_patterns_to_match; pn ++)                    \
245
    match = ((RA) == sighandler_calls[pn].ra_value);                        \
246
                                                                            \
247
  (SIGCTX) = (struct sigcontext *)                                          \
248
    (match ? ((CFA) + sighandler_calls[pn - 1].cfa_to_context_offset) : 0); \
249
} while (0);
250
 
251
#include <sys/context_t.h>
252
 
253
#define REG_SP  30  /* hard reg for stack pointer */
254
#define REG_RA  26  /* hard reg for return address */
255
 
256
#define MD_FALLBACK_FRAME_STATE_FOR alpha_fallback_frame_state
257
 
258
static _Unwind_Reason_Code
259
alpha_fallback_frame_state (struct _Unwind_Context *context,
260
                            _Unwind_FrameState *fs)
261
{
262
  /* Return address and CFA of the frame we're attempting to unwind through,
263
     possibly a signal handler.  */
264
  void *ctx_ra  = (void *)context->ra;
265
  void *ctx_cfa = (void *)context->cfa;
266
 
267
  /* CFA of the intermediate abstract kernel frame between the interrupted
268
     code and the signal handler, if we're indeed unwinding through a signal
269
     handler.  */
270
  void *k_cfa;
271
 
272
  /* Pointer to the sigcontext structure pushed by the kernel when we're
273
     unwinding through a signal handler.  */
274
  struct sigcontext *sigctx;
275
  int i;
276
 
277
  COMPUTE_SIGCONTEXT_FOR (ctx_ra, ctx_cfa, sigctx);
278
 
279
  if (sigctx == 0)
280
    return _URC_END_OF_STACK;
281
 
282
  /* The kernel frame's CFA is exactly the stack pointer value at the
283
     interruption point.  */
284
  k_cfa = (void *) sigctx->sc_regs [REG_SP];
285
 
286
  /* State the rules to compute the CFA we have the value of: use the
287
     previous CFA and offset by the difference between the two.  See
288
     uw_update_context_1 for the supporting details.  */
289
  fs->regs.cfa_how = CFA_REG_OFFSET;
290
  fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
291
  fs->regs.cfa_offset = k_cfa - ctx_cfa;
292
 
293
  /* Fill the internal frame_state structure with information stating
294
     where each register of interest in the saved context can be found
295
     from the CFA.  */
296
 
297
  /* The general registers are in sigctx->sc_regs.  Leave out r31, which
298
     is read-as-zero. It makes no sense restoring it, and we are going to
299
     use the state entry for the kernel return address rule below.
300
 
301
     This loop must cover at least all the callee-saved registers, and
302
     we just don't bother specializing the set here.  */
303
  for (i = 0; i <= 30; i ++)
304
    {
305
      fs->regs.reg[i].how = REG_SAVED_OFFSET;
306
      fs->regs.reg[i].loc.offset
307
        = (void *) &sigctx->sc_regs[i] - (void *) k_cfa;
308
    }
309
 
310
  /* Ditto for the floating point registers in sigctx->sc_fpregs.  */
311
  for (i = 0; i <= 31; i ++)
312
    {
313
      fs->regs.reg[32+i].how = REG_SAVED_OFFSET;
314
      fs->regs.reg[32+i].loc.offset
315
        = (void *) &sigctx->sc_fpregs[i] - (void *) k_cfa;
316
    }
317
 
318
  /* State the rules to find the kernel's code "return address", which
319
     is the address of the active instruction when the signal was caught,
320
     in sigctx->sc_pc. Use DWARF_ALT_FRAME_RETURN_COLUMN since the return
321
     address register is a general register and should be left alone.  */
322
  fs->retaddr_column = DWARF_ALT_FRAME_RETURN_COLUMN;
323
  fs->regs.reg[DWARF_ALT_FRAME_RETURN_COLUMN].how = REG_SAVED_OFFSET;
324
  fs->regs.reg[DWARF_ALT_FRAME_RETURN_COLUMN].loc.offset
325
    = (void *) &sigctx->sc_pc - (void *) k_cfa;
326
  fs->signal_frame = 1;
327
 
328
  return _URC_NO_REASON;
329
}

powered by: WebSVN 2.1.0

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