]>
Commit | Line | Data |
---|---|---|
e440a328 | 1 | /* go-signal.c -- signal handling for Go. |
2 | ||
3 | Copyright 2009 The Go Authors. All rights reserved. | |
4 | Use of this source code is governed by a BSD-style | |
5 | license that can be found in the LICENSE file. */ | |
6 | ||
7 | #include <signal.h> | |
8 | #include <stdlib.h> | |
6e7609c8 | 9 | #include <unistd.h> |
61b9e599 | 10 | #include <sys/time.h> |
87211034 | 11 | #include <ucontext.h> |
e440a328 | 12 | |
6e7609c8 | 13 | #include "runtime.h" |
e440a328 | 14 | |
61b9e599 | 15 | #ifndef SA_RESTART |
16 | #define SA_RESTART 0 | |
e440a328 | 17 | #endif |
18 | ||
dfcc5de0 | 19 | #ifdef USING_SPLIT_STACK |
e440a328 | 20 | |
dfcc5de0 | 21 | extern void __splitstack_getcontext(void *context[10]); |
e440a328 | 22 | |
dfcc5de0 | 23 | extern void __splitstack_setcontext(void *context[10]); |
e440a328 | 24 | |
87211034 | 25 | extern void *__splitstack_find_context(void *context[10], size_t *, |
26 | void **, void **, void **); | |
dfcc5de0 | 27 | |
e440a328 | 28 | #endif |
2d2d80b8 | 29 | |
87211034 | 30 | // The rest of the signal handler, written in Go. |
dfcc5de0 | 31 | |
87211034 | 32 | extern void sigtrampgo(uint32, siginfo_t *, void *) |
33 | __asm__(GOSYM_PREFIX "runtime.sigtrampgo"); | |
e440a328 | 34 | |
87211034 | 35 | // The Go signal handler, written in C. This should be running on the |
36 | // alternate signal stack. This is responsible for setting up the | |
37 | // split stack context so that stack guard checks will work as | |
38 | // expected. | |
dfcc5de0 | 39 | |
87211034 | 40 | void sigtramp(int, siginfo_t *, void *) |
41 | __attribute__ ((no_split_stack)); | |
f4ca453c | 42 | |
87211034 | 43 | void sigtramp(int, siginfo_t *, void *) |
44 | __asm__ (GOSYM_PREFIX "runtime.sigtramp"); | |
dfcc5de0 | 45 | |
87211034 | 46 | #ifndef USING_SPLIT_STACK |
dfcc5de0 | 47 | |
87211034 | 48 | // When not using split stacks, there are no stack checks, and there |
49 | // is nothing special for this function to do. | |
60d1da4c | 50 | |
87211034 | 51 | void |
52 | sigtramp(int sig, siginfo_t *info, void *context) | |
dfcc5de0 | 53 | { |
87211034 | 54 | sigtrampgo(sig, info, context); |
dfcc5de0 | 55 | } |
9c02c71b | 56 | |
87211034 | 57 | #else // USING_SPLIT_STACK |
e440a328 | 58 | |
87211034 | 59 | void |
60 | sigtramp(int sig, siginfo_t *info, void *context) | |
dfcc5de0 | 61 | { |
87211034 | 62 | G *gp; |
63 | void *stack_context[10]; | |
64 | void *stack; | |
65 | size_t stack_size; | |
66 | void *next_segment; | |
67 | void *next_sp; | |
68 | void *initial_sp; | |
69 | uintptr sp; | |
70 | stack_t st; | |
71 | uintptr stsp; | |
72 | ||
73 | gp = runtime_g(); | |
74 | ||
75 | if (gp == nil) { | |
76 | // Let the Go code handle this case. | |
77 | // It should only call nosplit functions in this case. | |
78 | sigtrampgo(sig, info, context); | |
79 | return; | |
80 | } | |
dfcc5de0 | 81 | |
87211034 | 82 | // If this signal is one for which we will panic, we are not |
83 | // on the alternate signal stack. It's OK to call split-stack | |
84 | // functions here. | |
85 | if (sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV) { | |
86 | sigtrampgo(sig, info, context); | |
87 | return; | |
dfcc5de0 | 88 | } |
e440a328 | 89 | |
87211034 | 90 | // We are running on the alternate signal stack. |
91 | ||
92 | __splitstack_getcontext(&stack_context[0]); | |
93 | ||
03118c21 | 94 | stack = __splitstack_find_context((void*)(&gp->m->gsignal->stackcontext[0]), |
87211034 | 95 | &stack_size, &next_segment, |
96 | &next_sp, &initial_sp); | |
97 | ||
98 | // If some non-Go code called sigaltstack, adjust. | |
99 | sp = (uintptr)(&stack_size); | |
100 | if (sp < (uintptr)(stack) || sp >= (uintptr)(stack) + stack_size) { | |
101 | sigaltstack(nil, &st); | |
102 | if ((st.ss_flags & SS_DISABLE) != 0) { | |
103 | runtime_printf("signal %d received on thread with no signal stack\n", (int32)(sig)); | |
104 | runtime_throw("non-Go code disabled sigaltstack"); | |
105 | } | |
106 | ||
107 | stsp = (uintptr)(st.ss_sp); | |
108 | if (sp < stsp || sp >= stsp + st.ss_size) { | |
109 | runtime_printf("signal %d received but handler not on signal stack\n", (int32)(sig)); | |
110 | runtime_throw("non-Go code set up signal handler without SA_ONSTACK flag"); | |
111 | } | |
112 | ||
113 | // Unfortunately __splitstack_find_context will return NULL | |
114 | // when it is called on a context that has never been used. | |
115 | // There isn't much we can do but assume all is well. | |
116 | if (stack != NULL) { | |
117 | // Here the gc runtime adjusts the gsignal | |
118 | // stack guard to match the values returned by | |
119 | // sigaltstack. Unfortunately we have no way | |
120 | // to do that. | |
121 | runtime_printf("signal %d received on unknown signal stack\n", (int32)(sig)); | |
122 | runtime_throw("non-Go code changed signal stack"); | |
123 | } | |
124 | } | |
6e7609c8 | 125 | |
87211034 | 126 | // Set the split stack context so that the stack guards are |
127 | // checked correctly. | |
e440a328 | 128 | |
03118c21 | 129 | __splitstack_setcontext((void*)(&gp->m->gsignal->stackcontext[0])); |
e440a328 | 130 | |
87211034 | 131 | sigtrampgo(sig, info, context); |
e440a328 | 132 | |
87211034 | 133 | // We are going to return back to the signal trampoline and |
134 | // then to whatever we were doing before we got the signal. | |
135 | // Restore the split stack context so that stack guards are | |
136 | // checked correctly. | |
dfcc5de0 | 137 | |
87211034 | 138 | __splitstack_setcontext(&stack_context[0]); |
e440a328 | 139 | } |
140 | ||
87211034 | 141 | #endif // USING_SPLIT_STACK |
dfcc5de0 | 142 | |
bc816275 | 143 | // C function to return the address of the sigtramp function. |
144 | uintptr getSigtramp(void) __asm__ (GOSYM_PREFIX "runtime.getSigtramp"); | |
145 | ||
146 | uintptr | |
147 | getSigtramp() | |
148 | { | |
149 | return (uintptr)(void*)sigtramp; | |
150 | } | |
151 | ||
87211034 | 152 | // C code to manage the sigaction sa_sigaction field, which is |
153 | // typically a union and so hard for mksysinfo.sh to handle. | |
dfcc5de0 | 154 | |
87211034 | 155 | uintptr getSigactionHandler(struct sigaction*) |
156 | __attribute__ ((no_split_stack)); | |
f4ca453c | 157 | |
87211034 | 158 | uintptr getSigactionHandler(struct sigaction*) |
159 | __asm__ (GOSYM_PREFIX "runtime.getSigactionHandler"); | |
f4ca453c | 160 | |
87211034 | 161 | uintptr |
162 | getSigactionHandler(struct sigaction* sa) | |
f4ca453c | 163 | { |
87211034 | 164 | return (uintptr)(sa->sa_sigaction); |
f4ca453c | 165 | } |
166 | ||
87211034 | 167 | void setSigactionHandler(struct sigaction*, uintptr) |
168 | __attribute__ ((no_split_stack)); | |
169 | ||
170 | void setSigactionHandler(struct sigaction*, uintptr) | |
171 | __asm__ (GOSYM_PREFIX "runtime.setSigactionHandler"); | |
f4ca453c | 172 | |
e440a328 | 173 | void |
87211034 | 174 | setSigactionHandler(struct sigaction* sa, uintptr handler) |
e440a328 | 175 | { |
87211034 | 176 | sa->sa_sigaction = (void*)(handler); |
e440a328 | 177 | } |
84911de8 | 178 | |
87211034 | 179 | // C code to fetch values from the siginfo_t and ucontext_t pointers |
180 | // passed to a signal handler. | |
f4ca453c | 181 | |
87211034 | 182 | struct getSiginfoRet { |
183 | uintptr sigaddr; | |
184 | uintptr sigpc; | |
185 | }; | |
84911de8 | 186 | |
87211034 | 187 | struct getSiginfoRet getSiginfo(siginfo_t *, void *) |
188 | __asm__(GOSYM_PREFIX "runtime.getSiginfo"); | |
84911de8 | 189 | |
87211034 | 190 | struct getSiginfoRet |
191 | getSiginfo(siginfo_t *info, void *context __attribute__((unused))) | |
84911de8 | 192 | { |
87211034 | 193 | struct getSiginfoRet ret; |
194 | Location loc[1]; | |
195 | int32 n; | |
196 | ||
cccf7f10 | 197 | if (info == nil) { |
198 | ret.sigaddr = 0; | |
199 | } else { | |
200 | ret.sigaddr = (uintptr)(info->si_addr); | |
201 | } | |
87211034 | 202 | ret.sigpc = 0; |
203 | ||
204 | // There doesn't seem to be a portable way to get the PC. | |
205 | // Use unportable code to pull it from context, and if that fails | |
206 | // try a stack backtrace across the signal handler. | |
207 | ||
208 | #ifdef __x86_64__ | |
209 | #ifdef __linux__ | |
210 | ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_RIP]; | |
211 | #endif | |
212 | #endif | |
213 | #ifdef __i386__ | |
214 | #ifdef __linux__ | |
215 | ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_EIP]; | |
216 | #endif | |
217 | #endif | |
522e3c6b | 218 | #ifdef __alpha__ |
219 | #ifdef __linux__ | |
220 | ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.sc_pc; | |
221 | #endif | |
222 | #endif | |
52722366 | 223 | #ifdef __PPC__ |
224 | #ifdef __linux__ | |
225 | ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.regs->nip; | |
226 | #endif | |
c32fbf74 | 227 | #ifdef _AIX |
228 | ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.jmp_context.iar; | |
229 | #endif | |
52722366 | 230 | #endif |
87211034 | 231 | |
232 | if (ret.sigpc == 0) { | |
233 | // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler. | |
234 | n = runtime_callers(5, &loc[0], 1, false); | |
235 | if (n > 0) { | |
236 | ret.sigpc = loc[0].pc; | |
237 | } | |
238 | } | |
84911de8 | 239 | |
87211034 | 240 | return ret; |
241 | } | |
84911de8 | 242 | |
87211034 | 243 | // Dump registers when crashing in a signal. |
244 | // There is no portable way to write this, | |
245 | // so we just have some CPU/OS specific implementations. | |
84911de8 | 246 | |
87211034 | 247 | void dumpregs(siginfo_t *, void *) |
248 | __asm__(GOSYM_PREFIX "runtime.dumpregs"); | |
2d2d80b8 | 249 | |
250 | void | |
87211034 | 251 | dumpregs(siginfo_t *info __attribute__((unused)), void *context __attribute__((unused))) |
2d2d80b8 | 252 | { |
87211034 | 253 | #ifdef __x86_64__ |
254 | #ifdef __linux__ | |
255 | { | |
256 | mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext; | |
257 | ||
258 | runtime_printf("rax %X\n", m->gregs[REG_RAX]); | |
259 | runtime_printf("rbx %X\n", m->gregs[REG_RBX]); | |
260 | runtime_printf("rcx %X\n", m->gregs[REG_RCX]); | |
261 | runtime_printf("rdx %X\n", m->gregs[REG_RDX]); | |
262 | runtime_printf("rdi %X\n", m->gregs[REG_RDI]); | |
263 | runtime_printf("rsi %X\n", m->gregs[REG_RSI]); | |
264 | runtime_printf("rbp %X\n", m->gregs[REG_RBP]); | |
265 | runtime_printf("rsp %X\n", m->gregs[REG_RSP]); | |
266 | runtime_printf("r8 %X\n", m->gregs[REG_R8]); | |
267 | runtime_printf("r9 %X\n", m->gregs[REG_R9]); | |
268 | runtime_printf("r10 %X\n", m->gregs[REG_R10]); | |
269 | runtime_printf("r11 %X\n", m->gregs[REG_R11]); | |
270 | runtime_printf("r12 %X\n", m->gregs[REG_R12]); | |
271 | runtime_printf("r13 %X\n", m->gregs[REG_R13]); | |
272 | runtime_printf("r14 %X\n", m->gregs[REG_R14]); | |
273 | runtime_printf("r15 %X\n", m->gregs[REG_R15]); | |
274 | runtime_printf("rip %X\n", m->gregs[REG_RIP]); | |
275 | runtime_printf("rflags %X\n", m->gregs[REG_EFL]); | |
276 | runtime_printf("cs %X\n", m->gregs[REG_CSGSFS] & 0xffff); | |
277 | runtime_printf("fs %X\n", (m->gregs[REG_CSGSFS] >> 16) & 0xffff); | |
278 | runtime_printf("gs %X\n", (m->gregs[REG_CSGSFS] >> 32) & 0xffff); | |
279 | } | |
280 | #endif | |
281 | #endif | |
282 | ||
283 | #ifdef __i386__ | |
284 | #ifdef __linux__ | |
285 | { | |
286 | mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext; | |
287 | ||
c32fbf74 | 288 | runtime_printf("eax %x\n", m->gregs[REG_EAX]); |
289 | runtime_printf("ebx %x\n", m->gregs[REG_EBX]); | |
290 | runtime_printf("ecx %x\n", m->gregs[REG_ECX]); | |
291 | runtime_printf("edx %x\n", m->gregs[REG_EDX]); | |
292 | runtime_printf("edi %x\n", m->gregs[REG_EDI]); | |
293 | runtime_printf("esi %x\n", m->gregs[REG_ESI]); | |
294 | runtime_printf("ebp %x\n", m->gregs[REG_EBP]); | |
295 | runtime_printf("esp %x\n", m->gregs[REG_ESP]); | |
296 | runtime_printf("eip %x\n", m->gregs[REG_EIP]); | |
297 | runtime_printf("eflags %x\n", m->gregs[REG_EFL]); | |
298 | runtime_printf("cs %x\n", m->gregs[REG_CS]); | |
299 | runtime_printf("fs %x\n", m->gregs[REG_FS]); | |
300 | runtime_printf("gs %x\n", m->gregs[REG_GS]); | |
87211034 | 301 | } |
302 | #endif | |
303 | #endif | |
a57f48a9 | 304 | |
305 | #ifdef __alpha__ | |
306 | #ifdef __linux__ | |
307 | { | |
308 | mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext; | |
309 | ||
310 | runtime_printf("v0 %X\n", m->sc_regs[0]); | |
311 | runtime_printf("t0 %X\n", m->sc_regs[1]); | |
312 | runtime_printf("t1 %X\n", m->sc_regs[2]); | |
313 | runtime_printf("t2 %X\n", m->sc_regs[3]); | |
314 | runtime_printf("t3 %X\n", m->sc_regs[4]); | |
315 | runtime_printf("t4 %X\n", m->sc_regs[5]); | |
316 | runtime_printf("t5 %X\n", m->sc_regs[6]); | |
317 | runtime_printf("t6 %X\n", m->sc_regs[7]); | |
318 | runtime_printf("t7 %X\n", m->sc_regs[8]); | |
319 | runtime_printf("s0 %X\n", m->sc_regs[9]); | |
320 | runtime_printf("s1 %X\n", m->sc_regs[10]); | |
321 | runtime_printf("s2 %X\n", m->sc_regs[11]); | |
322 | runtime_printf("s3 %X\n", m->sc_regs[12]); | |
323 | runtime_printf("s4 %X\n", m->sc_regs[13]); | |
324 | runtime_printf("s5 %X\n", m->sc_regs[14]); | |
325 | runtime_printf("fp %X\n", m->sc_regs[15]); | |
326 | runtime_printf("a0 %X\n", m->sc_regs[16]); | |
327 | runtime_printf("a1 %X\n", m->sc_regs[17]); | |
328 | runtime_printf("a2 %X\n", m->sc_regs[18]); | |
329 | runtime_printf("a3 %X\n", m->sc_regs[19]); | |
330 | runtime_printf("a4 %X\n", m->sc_regs[20]); | |
331 | runtime_printf("a5 %X\n", m->sc_regs[21]); | |
332 | runtime_printf("t8 %X\n", m->sc_regs[22]); | |
333 | runtime_printf("t9 %X\n", m->sc_regs[23]); | |
334 | runtime_printf("t10 %X\n", m->sc_regs[24]); | |
335 | runtime_printf("t11 %X\n", m->sc_regs[25]); | |
336 | runtime_printf("ra %X\n", m->sc_regs[26]); | |
337 | runtime_printf("t12 %X\n", m->sc_regs[27]); | |
338 | runtime_printf("at %X\n", m->sc_regs[28]); | |
339 | runtime_printf("gp %X\n", m->sc_regs[29]); | |
340 | runtime_printf("sp %X\n", m->sc_regs[30]); | |
341 | runtime_printf("pc %X\n", m->sc_pc); | |
342 | } | |
343 | #endif | |
344 | #endif | |
c32fbf74 | 345 | |
9839559a | 346 | #if defined(__PPC__) && defined(__LITTLE_ENDIAN__) |
c32fbf74 | 347 | #ifdef __linux__ |
348 | { | |
349 | mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext; | |
350 | int i; | |
351 | ||
352 | for (i = 0; i < 32; i++) | |
353 | runtime_printf("r%d %X\n", i, m->regs->gpr[i]); | |
354 | runtime_printf("pc %X\n", m->regs->nip); | |
355 | runtime_printf("msr %X\n", m->regs->msr); | |
356 | runtime_printf("cr %X\n", m->regs->ccr); | |
357 | runtime_printf("lr %X\n", m->regs->link); | |
358 | runtime_printf("ctr %X\n", m->regs->ctr); | |
359 | runtime_printf("xer %X\n", m->regs->xer); | |
360 | } | |
361 | #endif | |
9839559a | 362 | #endif |
363 | ||
364 | #ifdef __PPC__ | |
c32fbf74 | 365 | #ifdef _AIX |
366 | { | |
367 | mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext; | |
368 | int i; | |
369 | ||
370 | for (i = 0; i < 32; i++) | |
371 | runtime_printf("r%d %p\n", i, m->jmp_context.gpr[i]); | |
372 | runtime_printf("pc %p\n", m->jmp_context.iar); | |
373 | runtime_printf("msr %p\n", m->jmp_context.msr); | |
374 | runtime_printf("cr %x\n", m->jmp_context.cr); | |
375 | runtime_printf("lr %p\n", m->jmp_context.lr); | |
376 | runtime_printf("ctr %p\n", m->jmp_context.ctr); | |
377 | runtime_printf("xer %x\n", m->jmp_context.xer); | |
378 | } | |
379 | #endif | |
380 | #endif | |
2d2d80b8 | 381 | } |