1
0
mirror of https://github.com/golang/go synced 2024-11-20 02:24:43 -07:00
go/src/runtime/signal_arm.go
Russ Cox bf1de1b141 runtime: introduce GOTRACEBACK=single, now the default
Abandon (but still support) the old numbering system.

GOTRACEBACK=none is old 0
GOTRACEBACK=single is the new behavior
GOTRACEBACK=all is old 1
GOTRACEBACK=system is old 2
GOTRACEBACK=crash is unchanged

See doc comment change in runtime1.go for details.

Filed #13107 to decide whether to change default back to GOTRACEBACK=all for Go 1.6 release.
If you run into programs where printing only the current goroutine omits
needed information, please add details in a comment on that issue.

Fixes #12366.

Change-Id: I82ca8b99b5d86dceb3f7102d38d2659d45dbe0db
Reviewed-on: https://go-review.googlesource.com/16512
Reviewed-by: Austin Clements <austin@google.com>
2015-10-30 18:43:44 +00:00

166 lines
4.7 KiB
Go

// Copyright 2009 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
package runtime
import "unsafe"
func dumpregs(c *sigctxt) {
print("trap ", hex(c.trap()), "\n")
print("error ", hex(c.error()), "\n")
print("oldmask ", hex(c.oldmask()), "\n")
print("r0 ", hex(c.r0()), "\n")
print("r1 ", hex(c.r1()), "\n")
print("r2 ", hex(c.r2()), "\n")
print("r3 ", hex(c.r3()), "\n")
print("r4 ", hex(c.r4()), "\n")
print("r5 ", hex(c.r5()), "\n")
print("r6 ", hex(c.r6()), "\n")
print("r7 ", hex(c.r7()), "\n")
print("r8 ", hex(c.r8()), "\n")
print("r9 ", hex(c.r9()), "\n")
print("r10 ", hex(c.r10()), "\n")
print("fp ", hex(c.fp()), "\n")
print("ip ", hex(c.ip()), "\n")
print("sp ", hex(c.sp()), "\n")
print("lr ", hex(c.lr()), "\n")
print("pc ", hex(c.pc()), "\n")
print("cpsr ", hex(c.cpsr()), "\n")
print("fault ", hex(c.fault()), "\n")
}
var crashing int32
// May run during STW, so write barriers are not allowed.
//go:nowritebarrier
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
_g_ := getg()
c := &sigctxt{info, ctxt}
if sig == _SIGPROF {
sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp, _g_.m)
return
}
flags := int32(_SigThrow)
if sig < uint32(len(sigtable)) {
flags = sigtable[sig].flags
}
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
// Make it look like a call to the signal func.
// 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 = uintptr(c.pc())
// We arrange lr, and pc to pretend the panicking
// function calls sigpanic directly.
// Always save LR to stack so that panics in leaf
// functions are correctly handled. This smashes
// the stack frame but we're not going back there
// anyway.
sp := c.sp() - 4
c.set_sp(sp)
*(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
pc := uintptr(gp.sigpc)
// If we don't recognize the PC as code
// but we do recognize the link register as code,
// then assume this was a call to non-code and treat like
// pc == 0, to make unwinding show the context.
if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
pc = 0
}
// Don't bother saving PC if it's zero, which is
// probably a call to a nil func: the old link register
// is more useful in the stack trace.
if pc != 0 {
c.set_lr(uint32(pc))
}
// In case we are panicking from external C code
c.set_r10(uint32(uintptr(unsafe.Pointer(gp))))
c.set_pc(uint32(funcPC(sigpanic)))
return
}
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
if sigsend(sig) {
return
}
}
if flags&_SigKill != 0 {
exit(2)
}
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")
}
print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
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(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), 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)
traceback(^uintptr(0), ^uintptr(0), 0, gp)
} else if crashing == 0 {
tracebackothers(gp)
print("\n")
}
dumpregs(c)
}
if docrash {
crashing++
if crashing < sched.mcount {
// 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)
}