2016-09-23 23:05:51 -06:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
|
|
|
import (
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
// crashing is the number of m's we have waited for when implementing
|
|
|
|
// GOTRACEBACK=crash when a signal is received.
|
|
|
|
var crashing int32
|
|
|
|
|
|
|
|
// sighandler is invoked when a signal occurs. The global g will be
|
|
|
|
// set to a gsignal goroutine and we will be running on the alternate
|
|
|
|
// signal stack. The parameter g will be the value of the global g
|
|
|
|
// when the signal occurred. The sig, info, and ctxt parameters are
|
|
|
|
// from the system signal handler: they are the parameters passed when
|
|
|
|
// the SA is passed to the sigaction system call.
|
|
|
|
//
|
|
|
|
// The garbage collector may have stopped the world, so write barriers
|
|
|
|
// are not allowed.
|
|
|
|
//
|
|
|
|
//go:nowritebarrierrec
|
|
|
|
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
|
|
|
_g_ := getg()
|
|
|
|
c := &sigctxt{info, ctxt}
|
|
|
|
|
|
|
|
if sig == _SIGPROF {
|
|
|
|
sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
flags := int32(_SigThrow)
|
|
|
|
if sig < uint32(len(sigtable)) {
|
|
|
|
flags = sigtable[sig].flags
|
|
|
|
}
|
|
|
|
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
|
|
|
|
// The signal is going to cause a panic.
|
|
|
|
// Arrange the stack so that it looks like the point
|
|
|
|
// where the signal occurred made a call to the
|
|
|
|
// function sigpanic. Then set the PC to sigpanic.
|
|
|
|
|
|
|
|
// Have to pass arguments out of band since
|
|
|
|
// augmenting the stack frame would break
|
|
|
|
// the unwinding code.
|
|
|
|
gp.sig = sig
|
|
|
|
gp.sigcode0 = uintptr(c.sigcode())
|
|
|
|
gp.sigcode1 = uintptr(c.fault())
|
|
|
|
gp.sigpc = c.sigpc()
|
|
|
|
|
|
|
|
c.preparePanic(sig, gp)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
|
|
|
|
if sigsend(sig) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.sigcode() == _SI_USER && signal_ignored(sig) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if flags&_SigKill != 0 {
|
runtime: minor simplifications to signal code
Change setsig, setsigstack, getsig, raise, raiseproc to take uint32 for
signal number parameter, as that is the type mostly used for signal
numbers. Same for dieFromSignal, sigInstallGoHandler, raisebadsignal.
Remove setsig restart parameter, as it is always either true or
irrelevant.
Don't check the handler in setsigstack, as the only caller does that
anyhow.
Don't bother to convert the handler from sigtramp to sighandler in
getsig, as it will never be called when the handler is sigtramp or
sighandler.
Don't check the return value from rt_sigaction in the GNU/Linux version
of setsigstack; no other setsigstack checks it, and it never fails.
Change-Id: I6bbd677e048a77eddf974dd3d017bc3c560fbd48
Reviewed-on: https://go-review.googlesource.com/29953
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-09-27 23:24:51 -06:00
|
|
|
dieFromSignal(sig)
|
2016-09-23 23:05:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if flags&_SigThrow == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_g_.m.throwing = 1
|
|
|
|
_g_.m.caughtsig.set(gp)
|
|
|
|
|
|
|
|
if crashing == 0 {
|
|
|
|
startpanic()
|
|
|
|
}
|
|
|
|
|
|
|
|
if sig < uint32(len(sigtable)) {
|
|
|
|
print(sigtable[sig].name, "\n")
|
|
|
|
} else {
|
|
|
|
print("Signal ", sig, "\n")
|
|
|
|
}
|
|
|
|
|
2016-10-27 10:43:37 -06:00
|
|
|
print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
|
2016-09-23 23:05:51 -06:00
|
|
|
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
|
|
|
|
print("signal arrived during cgo execution\n")
|
|
|
|
gp = _g_.m.lockedg
|
|
|
|
}
|
|
|
|
print("\n")
|
|
|
|
|
|
|
|
level, _, docrash := gotraceback()
|
|
|
|
if level > 0 {
|
|
|
|
goroutineheader(gp)
|
|
|
|
tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
|
|
|
|
if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
|
|
|
|
// tracebackothers on original m skipped this one; trace it now.
|
|
|
|
goroutineheader(_g_.m.curg)
|
2017-03-10 08:59:39 -07:00
|
|
|
traceback(^uintptr(0), ^uintptr(0), 0, _g_.m.curg)
|
2016-09-23 23:05:51 -06:00
|
|
|
} else if crashing == 0 {
|
|
|
|
tracebackothers(gp)
|
|
|
|
print("\n")
|
|
|
|
}
|
|
|
|
dumpregs(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
if docrash {
|
|
|
|
crashing++
|
2017-03-15 12:48:23 -06:00
|
|
|
if crashing < sched.mcount-int32(extraMCount) {
|
2016-09-23 23:05:51 -06:00
|
|
|
// There are other m's that need to dump their stacks.
|
|
|
|
// Relay SIGQUIT to the next m by sending it to the current process.
|
|
|
|
// All m's that have already received SIGQUIT have signal masks blocking
|
|
|
|
// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
|
|
|
|
// When the last m receives the SIGQUIT, it will fall through to the call to
|
|
|
|
// crash below. Just in case the relaying gets botched, each m involved in
|
|
|
|
// the relay sleeps for 5 seconds and then does the crash/exit itself.
|
|
|
|
// In expected operation, the last m has received the SIGQUIT and run
|
|
|
|
// crash/exit and the process is gone, all long before any of the
|
|
|
|
// 5-second sleeps have finished.
|
|
|
|
print("\n-----\n\n")
|
|
|
|
raiseproc(_SIGQUIT)
|
|
|
|
usleep(5 * 1000 * 1000)
|
|
|
|
}
|
|
|
|
crash()
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(2)
|
|
|
|
}
|