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. */
19 #ifdef USING_SPLIT_STACK
21 extern void __splitstack_getcontext(void *context
[10]);
23 extern void __splitstack_setcontext(void *context
[10]);
25 extern void *__splitstack_find_context(void *context
[10], size_t *,
26 void **, void **, void **);
30 // The rest of the signal handler, written in Go.
32 extern void sigtrampgo(uint32
, siginfo_t
*, void *)
33 __asm__(GOSYM_PREFIX
"runtime.sigtrampgo");
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
40 void sigtramp(int, siginfo_t
*, void *)
41 __attribute__ ((no_split_stack
));
43 void sigtramp(int, siginfo_t
*, void *)
44 __asm__ (GOSYM_PREFIX
"runtime.sigtramp");
46 #ifndef USING_SPLIT_STACK
48 // When not using split stacks, there are no stack checks, and there
49 // is nothing special for this function to do.
52 sigtramp(int sig
, siginfo_t
*info
, void *context
)
54 sigtrampgo(sig
, info
, context
);
57 #else // USING_SPLIT_STACK
60 sigtramp(int sig
, siginfo_t
*info
, void *context
)
63 void *stack_context
[10];
76 // Let the Go code handle this case.
77 // It should only call nosplit functions in this case.
78 sigtrampgo(sig
, info
, context
);
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
85 if (sig
== SIGBUS
|| sig
== SIGFPE
|| sig
== SIGSEGV
) {
86 sigtrampgo(sig
, info
, context
);
90 // We are running on the alternate signal stack.
92 __splitstack_getcontext(&stack_context
[0]);
94 stack
= __splitstack_find_context(&gp
->m
->gsignal
->stackcontext
[0],
95 &stack_size
, &next_segment
,
96 &next_sp
, &initial_sp
);
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");
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");
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.
117 // Here the gc runtime adjusts the gsignal
118 // stack guard to match the values returned by
119 // sigaltstack. Unfortunately we have no way
121 runtime_printf("signal %d received on unknown signal stack\n", (int32
)(sig
));
122 runtime_throw("non-Go code changed signal stack");
126 // Set the split stack context so that the stack guards are
127 // checked correctly.
129 __splitstack_setcontext(&gp
->m
->gsignal
->stackcontext
[0]);
131 sigtrampgo(sig
, info
, context
);
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.
138 __splitstack_setcontext(&stack_context
[0]);
141 #endif // USING_SPLIT_STACK
143 // C function to return the address of the sigtramp function.
144 uintptr
getSigtramp(void) __asm__ (GOSYM_PREFIX
"runtime.getSigtramp");
149 return (uintptr
)(void*)sigtramp
;
152 // C code to manage the sigaction sa_sigaction field, which is
153 // typically a union and so hard for mksysinfo.sh to handle.
155 uintptr
getSigactionHandler(struct sigaction
*)
156 __attribute__ ((no_split_stack
));
158 uintptr
getSigactionHandler(struct sigaction
*)
159 __asm__ (GOSYM_PREFIX
"runtime.getSigactionHandler");
162 getSigactionHandler(struct sigaction
* sa
)
164 return (uintptr
)(sa
->sa_sigaction
);
167 void setSigactionHandler(struct sigaction
*, uintptr
)
168 __attribute__ ((no_split_stack
));
170 void setSigactionHandler(struct sigaction
*, uintptr
)
171 __asm__ (GOSYM_PREFIX
"runtime.setSigactionHandler");
174 setSigactionHandler(struct sigaction
* sa
, uintptr handler
)
176 sa
->sa_sigaction
= (void*)(handler
);
179 // C code to fetch values from the siginfo_t and ucontext_t pointers
180 // passed to a signal handler.
182 struct getSiginfoRet
{
187 struct getSiginfoRet
getSiginfo(siginfo_t
*, void *)
188 __asm__(GOSYM_PREFIX
"runtime.getSiginfo");
191 getSiginfo(siginfo_t
*info
, void *context
__attribute__((unused
)))
193 struct getSiginfoRet ret
;
200 ret
.sigaddr
= (uintptr
)(info
->si_addr
);
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.
210 ret
.sigpc
= ((ucontext_t
*)(context
))->uc_mcontext
.gregs
[REG_RIP
];
215 ret
.sigpc
= ((ucontext_t
*)(context
))->uc_mcontext
.gregs
[REG_EIP
];
219 if (ret
.sigpc
== 0) {
220 // Skip getSiginfo/sighandler/sigtrampgo/sigtramp/handler.
221 n
= runtime_callers(5, &loc
[0], 1, false);
223 ret
.sigpc
= loc
[0].pc
;
230 // Dump registers when crashing in a signal.
231 // There is no portable way to write this,
232 // so we just have some CPU/OS specific implementations.
234 void dumpregs(siginfo_t
*, void *)
235 __asm__(GOSYM_PREFIX
"runtime.dumpregs");
238 dumpregs(siginfo_t
*info
__attribute__((unused
)), void *context
__attribute__((unused
)))
243 mcontext_t
*m
= &((ucontext_t
*)(context
))->uc_mcontext
;
245 runtime_printf("rax %X\n", m
->gregs
[REG_RAX
]);
246 runtime_printf("rbx %X\n", m
->gregs
[REG_RBX
]);
247 runtime_printf("rcx %X\n", m
->gregs
[REG_RCX
]);
248 runtime_printf("rdx %X\n", m
->gregs
[REG_RDX
]);
249 runtime_printf("rdi %X\n", m
->gregs
[REG_RDI
]);
250 runtime_printf("rsi %X\n", m
->gregs
[REG_RSI
]);
251 runtime_printf("rbp %X\n", m
->gregs
[REG_RBP
]);
252 runtime_printf("rsp %X\n", m
->gregs
[REG_RSP
]);
253 runtime_printf("r8 %X\n", m
->gregs
[REG_R8
]);
254 runtime_printf("r9 %X\n", m
->gregs
[REG_R9
]);
255 runtime_printf("r10 %X\n", m
->gregs
[REG_R10
]);
256 runtime_printf("r11 %X\n", m
->gregs
[REG_R11
]);
257 runtime_printf("r12 %X\n", m
->gregs
[REG_R12
]);
258 runtime_printf("r13 %X\n", m
->gregs
[REG_R13
]);
259 runtime_printf("r14 %X\n", m
->gregs
[REG_R14
]);
260 runtime_printf("r15 %X\n", m
->gregs
[REG_R15
]);
261 runtime_printf("rip %X\n", m
->gregs
[REG_RIP
]);
262 runtime_printf("rflags %X\n", m
->gregs
[REG_EFL
]);
263 runtime_printf("cs %X\n", m
->gregs
[REG_CSGSFS
] & 0xffff);
264 runtime_printf("fs %X\n", (m
->gregs
[REG_CSGSFS
] >> 16) & 0xffff);
265 runtime_printf("gs %X\n", (m
->gregs
[REG_CSGSFS
] >> 32) & 0xffff);
273 mcontext_t
*m
= &((ucontext_t
*)(context
))->uc_mcontext
;
275 runtime_printf("eax %X\n", m
->gregs
[REG_EAX
]);
276 runtime_printf("ebx %X\n", m
->gregs
[REG_EBX
]);
277 runtime_printf("ecx %X\n", m
->gregs
[REG_ECX
]);
278 runtime_printf("edx %X\n", m
->gregs
[REG_EDX
]);
279 runtime_printf("edi %X\n", m
->gregs
[REG_EDI
]);
280 runtime_printf("esi %X\n", m
->gregs
[REG_ESI
]);
281 runtime_printf("ebp %X\n", m
->gregs
[REG_EBP
]);
282 runtime_printf("esp %X\n", m
->gregs
[REG_ESP
]);
283 runtime_printf("eip %X\n", m
->gregs
[REG_EIP
]);
284 runtime_printf("eflags %X\n", m
->gregs
[REG_EFL
]);
285 runtime_printf("cs %X\n", m
->gregs
[REG_CS
]);
286 runtime_printf("fs %X\n", m
->gregs
[REG_FS
]);
287 runtime_printf("gs %X\n", m
->gregs
[REG_GS
]);