1
0
mirror of https://github.com/golang/go synced 2024-10-02 12:28:33 -06:00
go/src/runtime/signal_windows.go
Ian Lance Taylor eb268cb321 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-28 13:12:47 +00:00

226 lines
6.0 KiB
Go

// Copyright 2011 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.
package runtime
import (
"unsafe"
)
func disableWER() {
// do not display Windows Error Reporting dialogue
const (
SEM_FAILCRITICALERRORS = 0x0001
SEM_NOGPFAULTERRORBOX = 0x0002
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
SEM_NOOPENFILEERRORBOX = 0x8000
)
errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
}
// in sys_windows_386.s and sys_windows_amd64.s
func exceptiontramp()
func firstcontinuetramp()
func lastcontinuetramp()
func initExceptionHandler() {
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
// use SetUnhandledExceptionFilter for windows-386 or
// if VectoredContinueHandler is unavailable.
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
} else {
stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
}
}
func isgoexception(info *exceptionrecord, r *context) bool {
// Only handle exception if executing instructions in Go binary
// (not Windows library code).
// TODO(mwhudson): needs to loop to support shared libs
if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
return false
}
// Go will only handle some exceptions.
switch info.exceptioncode {
default:
return false
case _EXCEPTION_ACCESS_VIOLATION:
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
case _EXCEPTION_INT_OVERFLOW:
case _EXCEPTION_FLT_DENORMAL_OPERAND:
case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
case _EXCEPTION_FLT_INEXACT_RESULT:
case _EXCEPTION_FLT_OVERFLOW:
case _EXCEPTION_FLT_UNDERFLOW:
case _EXCEPTION_BREAKPOINT:
}
return true
}
// Called by sigtramp from Windows VEH handler.
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
if !isgoexception(info, r) {
return _EXCEPTION_CONTINUE_SEARCH
}
// 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 = info.exceptioncode
gp.sigcode0 = uintptr(info.exceptioninformation[0])
gp.sigcode1 = uintptr(info.exceptioninformation[1])
gp.sigpc = r.ip()
// Only push runtime·sigpanic if r.ip() != 0.
// If r.ip() == 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 r.ip() != 0 {
sp := unsafe.Pointer(r.sp())
sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
*((*uintptr)(sp)) = r.ip()
r.setsp(uintptr(sp))
}
r.setip(funcPC(sigpanic))
return _EXCEPTION_CONTINUE_EXECUTION
}
// It seems Windows searches ContinueHandler's list even
// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
// firstcontinuehandler will stop that search,
// if exceptionhandler did the same earlier.
func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
if !isgoexception(info, r) {
return _EXCEPTION_CONTINUE_SEARCH
}
return _EXCEPTION_CONTINUE_EXECUTION
}
var testingWER bool
// lastcontinuehandler is reached, because runtime cannot handle
// current exception. lastcontinuehandler will print crash info and exit.
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
if testingWER {
return _EXCEPTION_CONTINUE_SEARCH
}
_g_ := getg()
if panicking != 0 { // traceback already printed
exit(2)
}
panicking = 1
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
print("PC=", hex(r.ip()), "\n")
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
if iscgo {
print("signal arrived during external code execution\n")
}
gp = _g_.m.lockedg
}
print("\n")
level, _, docrash := gotraceback()
if level > 0 {
tracebacktrap(r.ip(), r.sp(), 0, gp)
tracebackothers(gp)
dumpregs(r)
}
if docrash {
crash()
}
exit(2)
return 0 // not reached
}
func sigpanic() {
g := getg()
if !canpanic(g) {
throw("unexpected signal during runtime execution")
}
switch g.sig {
case _EXCEPTION_ACCESS_VIOLATION:
if g.sigcode1 < 0x1000 || g.paniconfault {
panicmem()
}
print("unexpected fault address ", hex(g.sigcode1), "\n")
throw("fault")
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
panicdivide()
case _EXCEPTION_INT_OVERFLOW:
panicoverflow()
case _EXCEPTION_FLT_DENORMAL_OPERAND,
_EXCEPTION_FLT_DIVIDE_BY_ZERO,
_EXCEPTION_FLT_INEXACT_RESULT,
_EXCEPTION_FLT_OVERFLOW,
_EXCEPTION_FLT_UNDERFLOW:
panicfloat()
}
throw("fault")
}
var (
badsignalmsg [100]byte
badsignallen int32
)
func setBadSignalMsg() {
const msg = "runtime: signal received on thread not created by Go.\n"
for i, c := range msg {
badsignalmsg[i] = byte(c)
badsignallen++
}
}
// Following are not implemented.
func initsig(preinit bool) {
}
func sigenable(sig uint32) {
}
func sigdisable(sig uint32) {
}
func sigignore(sig uint32) {
}
func badsignal2()
func raisebadsignal(sig uint32) {
badsignal2()
}
func signame(sig uint32) string {
return ""
}
func crash() {
// TODO: This routine should do whatever is needed
// to make the Windows program abort/crash as it
// would if Go was not intercepting signals.
// On Unix the routine would remove the custom signal
// handler and then raise a signal (like SIGABRT).
// Something like that should happen here.
// It's okay to leave this empty for now: if crash returns
// the ordinary exit-after-panic happens.
}