]>
Commit | Line | Data |
---|---|---|
6c175675 OH |
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 | } |