runtime: don't crash if signal handler info argument is nil
[official-gcc.git] / libgo / runtime / go-signal.c
blobb844dc59b7cd0085abd7eb87c8e040fd6a743ebb
1 /* go-signal.c -- signal handling for Go.
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. */
7 #include <signal.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/time.h>
11 #include <ucontext.h>
13 #include "runtime.h"
14 #include "go-assert.h"
15 #include "go-panic.h"
17 #ifndef SA_RESTART
18 #define SA_RESTART 0
19 #endif
21 #ifdef USING_SPLIT_STACK
23 extern void __splitstack_getcontext(void *context[10]);
25 extern void __splitstack_setcontext(void *context[10]);
27 extern void *__splitstack_find_context(void *context[10], size_t *,
28 void **, void **, void **);
30 #endif
32 // The rest of the signal handler, written in Go.
34 extern void sigtrampgo(uint32, siginfo_t *, void *)
35 __asm__(GOSYM_PREFIX "runtime.sigtrampgo");
37 // The Go signal handler, written in C. This should be running on the
38 // alternate signal stack. This is responsible for setting up the
39 // split stack context so that stack guard checks will work as
40 // expected.
42 void sigtramp(int, siginfo_t *, void *)
43 __attribute__ ((no_split_stack));
45 void sigtramp(int, siginfo_t *, void *)
46 __asm__ (GOSYM_PREFIX "runtime.sigtramp");
48 #ifndef USING_SPLIT_STACK
50 // When not using split stacks, there are no stack checks, and there
51 // is nothing special for this function to do.
53 void
54 sigtramp(int sig, siginfo_t *info, void *context)
56 sigtrampgo(sig, info, context);
59 #else // USING_SPLIT_STACK
61 void
62 sigtramp(int sig, siginfo_t *info, void *context)
64 G *gp;
65 void *stack_context[10];
66 void *stack;
67 size_t stack_size;
68 void *next_segment;
69 void *next_sp;
70 void *initial_sp;
71 uintptr sp;
72 stack_t st;
73 uintptr stsp;
75 gp = runtime_g();
77 if (gp == nil) {
78 // Let the Go code handle this case.
79 // It should only call nosplit functions in this case.
80 sigtrampgo(sig, info, context);
81 return;
84 // If this signal is one for which we will panic, we are not
85 // on the alternate signal stack. It's OK to call split-stack
86 // functions here.
87 if (sig == SIGBUS || sig == SIGFPE || sig == SIGSEGV) {
88 sigtrampgo(sig, info, context);
89 return;
92 // We are running on the alternate signal stack.
94 __splitstack_getcontext(&stack_context[0]);
96 stack = __splitstack_find_context(&gp->m->gsignal->stackcontext[0],
97 &stack_size, &next_segment,
98 &next_sp, &initial_sp);
100 // If some non-Go code called sigaltstack, adjust.
101 sp = (uintptr)(&stack_size);
102 if (sp < (uintptr)(stack) || sp >= (uintptr)(stack) + stack_size) {
103 sigaltstack(nil, &st);
104 if ((st.ss_flags & SS_DISABLE) != 0) {
105 runtime_printf("signal %d received on thread with no signal stack\n", (int32)(sig));
106 runtime_throw("non-Go code disabled sigaltstack");
109 stsp = (uintptr)(st.ss_sp);
110 if (sp < stsp || sp >= stsp + st.ss_size) {
111 runtime_printf("signal %d received but handler not on signal stack\n", (int32)(sig));
112 runtime_throw("non-Go code set up signal handler without SA_ONSTACK flag");
115 // Unfortunately __splitstack_find_context will return NULL
116 // when it is called on a context that has never been used.
117 // There isn't much we can do but assume all is well.
118 if (stack != NULL) {
119 // Here the gc runtime adjusts the gsignal
120 // stack guard to match the values returned by
121 // sigaltstack. Unfortunately we have no way
122 // to do that.
123 runtime_printf("signal %d received on unknown signal stack\n", (int32)(sig));
124 runtime_throw("non-Go code changed signal stack");
128 // Set the split stack context so that the stack guards are
129 // checked correctly.
131 __splitstack_setcontext(&gp->m->gsignal->stackcontext[0]);
133 sigtrampgo(sig, info, context);
135 // We are going to return back to the signal trampoline and
136 // then to whatever we were doing before we got the signal.
137 // Restore the split stack context so that stack guards are
138 // checked correctly.
140 __splitstack_setcontext(&stack_context[0]);
143 #endif // USING_SPLIT_STACK
145 // C code to manage the sigaction sa_sigaction field, which is
146 // typically a union and so hard for mksysinfo.sh to handle.
148 uintptr getSigactionHandler(struct sigaction*)
149 __attribute__ ((no_split_stack));
151 uintptr getSigactionHandler(struct sigaction*)
152 __asm__ (GOSYM_PREFIX "runtime.getSigactionHandler");
154 uintptr
155 getSigactionHandler(struct sigaction* sa)
157 return (uintptr)(sa->sa_sigaction);
160 void setSigactionHandler(struct sigaction*, uintptr)
161 __attribute__ ((no_split_stack));
163 void setSigactionHandler(struct sigaction*, uintptr)
164 __asm__ (GOSYM_PREFIX "runtime.setSigactionHandler");
166 void
167 setSigactionHandler(struct sigaction* sa, uintptr handler)
169 sa->sa_sigaction = (void*)(handler);
172 // C code to fetch values from the siginfo_t and ucontext_t pointers
173 // passed to a signal handler.
175 struct getSiginfoRet {
176 uintptr sigaddr;
177 uintptr sigpc;
180 struct getSiginfoRet getSiginfo(siginfo_t *, void *)
181 __asm__(GOSYM_PREFIX "runtime.getSiginfo");
183 struct getSiginfoRet
184 getSiginfo(siginfo_t *info, void *context __attribute__((unused)))
186 struct getSiginfoRet ret;
187 Location loc[1];
188 int32 n;
190 if (info == nil) {
191 ret.sigaddr = 0;
192 } else {
193 ret.sigaddr = (uintptr)(info->si_addr);
195 ret.sigpc = 0;
197 // There doesn't seem to be a portable way to get the PC.
198 // Use unportable code to pull it from context, and if that fails
199 // try a stack backtrace across the signal handler.
201 #ifdef __x86_64__
202 #ifdef __linux__
203 ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_RIP];
204 #endif
205 #endif
206 #ifdef __i386__
207 #ifdef __linux__
208 ret.sigpc = ((ucontext_t*)(context))->uc_mcontext.gregs[REG_EIP];
209 #endif
210 #endif
212 if (ret.sigpc == 0) {
213 // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler.
214 n = runtime_callers(5, &loc[0], 1, false);
215 if (n > 0) {
216 ret.sigpc = loc[0].pc;
220 return ret;
223 // Dump registers when crashing in a signal.
224 // There is no portable way to write this,
225 // so we just have some CPU/OS specific implementations.
227 void dumpregs(siginfo_t *, void *)
228 __asm__(GOSYM_PREFIX "runtime.dumpregs");
230 void
231 dumpregs(siginfo_t *info __attribute__((unused)), void *context __attribute__((unused)))
233 #ifdef __x86_64__
234 #ifdef __linux__
236 mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
238 runtime_printf("rax %X\n", m->gregs[REG_RAX]);
239 runtime_printf("rbx %X\n", m->gregs[REG_RBX]);
240 runtime_printf("rcx %X\n", m->gregs[REG_RCX]);
241 runtime_printf("rdx %X\n", m->gregs[REG_RDX]);
242 runtime_printf("rdi %X\n", m->gregs[REG_RDI]);
243 runtime_printf("rsi %X\n", m->gregs[REG_RSI]);
244 runtime_printf("rbp %X\n", m->gregs[REG_RBP]);
245 runtime_printf("rsp %X\n", m->gregs[REG_RSP]);
246 runtime_printf("r8 %X\n", m->gregs[REG_R8]);
247 runtime_printf("r9 %X\n", m->gregs[REG_R9]);
248 runtime_printf("r10 %X\n", m->gregs[REG_R10]);
249 runtime_printf("r11 %X\n", m->gregs[REG_R11]);
250 runtime_printf("r12 %X\n", m->gregs[REG_R12]);
251 runtime_printf("r13 %X\n", m->gregs[REG_R13]);
252 runtime_printf("r14 %X\n", m->gregs[REG_R14]);
253 runtime_printf("r15 %X\n", m->gregs[REG_R15]);
254 runtime_printf("rip %X\n", m->gregs[REG_RIP]);
255 runtime_printf("rflags %X\n", m->gregs[REG_EFL]);
256 runtime_printf("cs %X\n", m->gregs[REG_CSGSFS] & 0xffff);
257 runtime_printf("fs %X\n", (m->gregs[REG_CSGSFS] >> 16) & 0xffff);
258 runtime_printf("gs %X\n", (m->gregs[REG_CSGSFS] >> 32) & 0xffff);
260 #endif
261 #endif
263 #ifdef __i386__
264 #ifdef __linux__
266 mcontext_t *m = &((ucontext_t*)(context))->uc_mcontext;
268 runtime_printf("eax %X\n", m->gregs[REG_EAX]);
269 runtime_printf("ebx %X\n", m->gregs[REG_EBX]);
270 runtime_printf("ecx %X\n", m->gregs[REG_ECX]);
271 runtime_printf("edx %X\n", m->gregs[REG_EDX]);
272 runtime_printf("edi %X\n", m->gregs[REG_EDI]);
273 runtime_printf("esi %X\n", m->gregs[REG_ESI]);
274 runtime_printf("ebp %X\n", m->gregs[REG_EBP]);
275 runtime_printf("esp %X\n", m->gregs[REG_ESP]);
276 runtime_printf("eip %X\n", m->gregs[REG_EIP]);
277 runtime_printf("eflags %X\n", m->gregs[REG_EFL]);
278 runtime_printf("cs %X\n", m->gregs[REG_CS]);
279 runtime_printf("fs %X\n", m->gregs[REG_FS]);
280 runtime_printf("gs %X\n", m->gregs[REG_GS]);
282 #endif
283 #endif