mirror of
https://github.com/golang/go
synced 2024-11-19 15:44:44 -07:00
runtime: move all exception related code into signal_windows.go
Change-Id: I9654a5c85bd9b3ae9c7a9eddaef1ec752f42bd1b Reviewed-on: https://go-review.googlesource.com/8840 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
e6092d64a7
commit
d1af6bed84
@ -117,12 +117,6 @@ func loadOptionalSyscalls() {
|
||||
}
|
||||
}
|
||||
|
||||
// in sys_windows_386.s and sys_windows_amd64.s
|
||||
func externalthreadhandler()
|
||||
func exceptiontramp()
|
||||
func firstcontinuetramp()
|
||||
func lastcontinuetramp()
|
||||
|
||||
//go:nosplit
|
||||
func getLoadLibrary() uintptr {
|
||||
return uintptr(unsafe.Pointer(_LoadLibraryW))
|
||||
@ -144,24 +138,15 @@ const (
|
||||
currentThread = ^uintptr(1) // -2 = current thread
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func getVersion() (major, minor byte) {
|
||||
v := uint32(stdcall0(_GetVersion))
|
||||
low := uint16(v)
|
||||
return byte(low), byte(low >> 8)
|
||||
}
|
||||
|
||||
// in sys_windows_386.s and sys_windows_amd64.s
|
||||
func externalthreadhandler()
|
||||
|
||||
func osinit() {
|
||||
asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
|
||||
|
||||
@ -173,21 +158,7 @@ func osinit() {
|
||||
|
||||
externalthreadhandlerp = funcPC(externalthreadhandler)
|
||||
|
||||
major, _ := getVersion()
|
||||
|
||||
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
|
||||
if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
|
||||
// use SetUnhandledExceptionFilter for windows-386 or
|
||||
// if VectoredContinueHandler is unavailable or
|
||||
// if running windows-amd64 v5. V5 appears to fail to
|
||||
// call the continue handlers if windows error reporting dialog
|
||||
// is disabled.
|
||||
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
|
||||
stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
|
||||
} else {
|
||||
stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
|
||||
stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
|
||||
}
|
||||
initExceptionHandler()
|
||||
|
||||
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
||||
|
||||
@ -482,37 +453,6 @@ func usleep(us uint32) {
|
||||
usleep1(10 * us)
|
||||
}
|
||||
|
||||
func issigpanic(code uint32) uint32 {
|
||||
switch code {
|
||||
default:
|
||||
return 0
|
||||
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 1
|
||||
}
|
||||
|
||||
func initsig() {
|
||||
/*
|
||||
// TODO(brainman): I don't think we need that bit of code
|
||||
// following line keeps these functions alive at link stage
|
||||
// if there's a better way please write it here
|
||||
void *e = runtime·exceptiontramp;
|
||||
void *f = runtime·firstcontinuetramp;
|
||||
void *l = runtime·lastcontinuetramp;
|
||||
USED(e);
|
||||
USED(f);
|
||||
USED(l);
|
||||
*/
|
||||
}
|
||||
|
||||
func ctrlhandler1(_type uint32) uint32 {
|
||||
var s uint32
|
||||
|
||||
@ -604,35 +544,3 @@ func resetcpuprofiler(hz int32) {
|
||||
func memlimit() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
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++
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
_SIGPROF = 0 // dummy value for badsignal
|
||||
_SIGQUIT = 0 // dummy value for sighandler
|
||||
)
|
||||
|
||||
func raiseproc(sig int32) {
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
@ -13,33 +13,6 @@ func os_sigpipe() {
|
||||
throw("too many writes on closed pipe")
|
||||
}
|
||||
|
||||
func sigpanic() {
|
||||
g := getg()
|
||||
if !canpanic(g) {
|
||||
throw("unexpected signal during runtime execution")
|
||||
}
|
||||
|
||||
switch uint32(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")
|
||||
}
|
||||
|
||||
// Stubs so tests can link correctly. These should never be called.
|
||||
func open(name *byte, mode, perm int32) int32 {
|
||||
throw("unimplemented")
|
||||
|
@ -8,6 +8,40 @@ 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() {
|
||||
major, _ := getVersion()
|
||||
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
|
||||
if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
|
||||
// use SetUnhandledExceptionFilter for windows-386 or
|
||||
// if VectoredContinueHandler is unavailable or
|
||||
// if running windows-amd64 v5. V5 appears to fail to
|
||||
// call the continue handlers if windows error reporting dialog
|
||||
// is disabled.
|
||||
// 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).
|
||||
@ -16,17 +50,26 @@ func isgoexception(info *exceptionrecord, r *context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if issigpanic(info.exceptioncode) == 0 {
|
||||
// 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
|
||||
@ -108,6 +151,51 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
|
||||
return 0 // not reached
|
||||
}
|
||||
|
||||
func sigpanic() {
|
||||
g := getg()
|
||||
if !canpanic(g) {
|
||||
throw("unexpected signal during runtime execution")
|
||||
}
|
||||
|
||||
switch uint32(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() {
|
||||
}
|
||||
|
||||
func sigenable(sig uint32) {
|
||||
}
|
||||
|
||||
@ -116,3 +204,14 @@ func sigdisable(sig uint32) {
|
||||
|
||||
func sigignore(sig uint32) {
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user