comparison gcc/config/alpha/osf5-unwind.h @ 68:561a7518be6b

update gcc-4.6
author Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp>
date Sun, 21 Aug 2011 07:07:55 +0900
parents
children
comparison
equal deleted inserted replaced
67:f6334be47118 68:561a7518be6b
1 /* 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 }