diff options
author | Ian Lance Taylor <iant@golang.org> | 2016-09-23 22:05:51 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2016-09-25 03:55:33 +0000 |
commit | 159a90b93a962cb942688f099b42d00d164e436f (patch) | |
tree | 5742f50b4f74e1284512a50cf55dacb6cbf1f7ee /src/runtime/signal_386.go | |
parent | 890c09efb72f11b3e6fd95d859260bfee7de7f31 (diff) | |
download | go-159a90b93a962cb942688f099b42d00d164e436f.tar.gz go-159a90b93a962cb942688f099b42d00d164e436f.zip |
runtime: merge Unix sighandler functions
Replace all the Unix sighandler functions with a single instance.
Push the relatively small amount of processor-specific code into five
methods on sigctxt: sigpc, sigsp, siglr, fault, preparePanic.
(Some processors already had a fault method.)
Change-Id: Ib459412ff8f7e0f5ad06bfd43eb827c8b196fc32
Reviewed-on: https://go-review.googlesource.com/29752
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Diffstat (limited to 'src/runtime/signal_386.go')
-rw-r--r-- | src/runtime/signal_386.go | 178 |
1 files changed, 40 insertions, 138 deletions
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index f27cf9d8e2..502d502e6f 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -27,152 +27,54 @@ func dumpregs(c *sigctxt) { print("gs ", hex(c.gs()), "\n") } -var crashing int32 - -// May run during STW, 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(uintptr(c.eip()), uintptr(c.esp()), 0, 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.sigaddr()) - gp.sigpc = uintptr(c.eip()) - - if GOOS == "darwin" { - // Work around Leopard bug that doesn't set FPE_INTDIV. - // Look at instruction to see if it is a divide. - // Not necessary in Snow Leopard (si_code will be != 0). - if sig == _SIGFPE && gp.sigcode0 == 0 { - pc := (*[4]byte)(unsafe.Pointer(gp.sigpc)) - i := 0 - if pc[i] == 0x66 { // 16-bit instruction prefix - i++ - } - if pc[i] == 0xF6 || pc[i] == 0xF7 { - gp.sigcode0 = _FPE_INTDIV - } +func (c *sigctxt) sigpc() uintptr { return uintptr(c.eip()) } +func (c *sigctxt) sigsp() uintptr { return uintptr(c.esp()) } +func (c *sigctxt) siglr() uintptr { return 0 } +func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) } + +// preparePanic sets up the stack to look like a call to sigpanic. +func (c *sigctxt) preparePanic(sig uint32, gp *g) { + if GOOS == "darwin" { + // Work around Leopard bug that doesn't set FPE_INTDIV. + // Look at instruction to see if it is a divide. + // Not necessary in Snow Leopard (si_code will be != 0). + if sig == _SIGFPE && gp.sigcode0 == 0 { + pc := (*[4]byte)(unsafe.Pointer(gp.sigpc)) + i := 0 + if pc[i] == 0x66 { // 16-bit instruction prefix + i++ } - } - - pc := uintptr(c.eip()) - sp := uintptr(c.esp()) - - // If we don't recognize the PC as code - // but we do recognize the top pointer on the stack 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)(unsafe.Pointer(sp))) != nil { - pc = 0 - } - - // Only push runtime.sigpanic if pc != 0. - // If pc == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime.sigpanic instead. - // (Otherwise the trace will end at runtime.sigpanic and we - // won't get to see who faulted.) - if pc != 0 { - if sys.RegSize > sys.PtrSize { - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = 0 + if pc[i] == 0xF6 || pc[i] == 0xF7 { + gp.sigcode0 = _FPE_INTDIV } - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = pc - c.set_esp(uint32(sp)) - } - c.set_eip(uint32(funcPC(sigpanic))) - 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 { - dieFromSignal(int32(sig)) - } - - if flags&_SigThrow == 0 { - return - } - - _g_.m.throwing = 1 - _g_.m.caughtsig.set(gp) - - if crashing == 0 { - startpanic() - } + pc := uintptr(c.eip()) + sp := uintptr(c.esp()) - if sig < uint32(len(sigtable)) { - print(sigtable[sig].name, "\n") - } else { - print("Signal ", sig, "\n") + // If we don't recognize the PC as code + // but we do recognize the top pointer on the stack 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)(unsafe.Pointer(sp))) != nil { + pc = 0 } - print("PC=", hex(c.eip()), " 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.eip()), uintptr(c.esp()), 0, 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) + // Only push runtime.sigpanic if pc != 0. + // If pc == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime.sigpanic instead. + // (Otherwise the trace will end at runtime.sigpanic and we + // won't get to see who faulted.) + if pc != 0 { + if sys.RegSize > sys.PtrSize { + sp -= sys.PtrSize + *(*uintptr)(unsafe.Pointer(sp)) = 0 } - crash() + sp -= sys.PtrSize + *(*uintptr)(unsafe.Pointer(sp)) = pc + c.set_esp(uint32(sp)) } - - exit(2) + c.set_eip(uint32(funcPC(sigpanic))) } |