mirror of
https://github.com/golang/go
synced 2024-11-19 16:44:43 -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
|
//go:nosplit
|
||||||
func getLoadLibrary() uintptr {
|
func getLoadLibrary() uintptr {
|
||||||
return uintptr(unsafe.Pointer(_LoadLibraryW))
|
return uintptr(unsafe.Pointer(_LoadLibraryW))
|
||||||
@ -144,24 +138,15 @@ const (
|
|||||||
currentThread = ^uintptr(1) // -2 = current thread
|
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) {
|
func getVersion() (major, minor byte) {
|
||||||
v := uint32(stdcall0(_GetVersion))
|
v := uint32(stdcall0(_GetVersion))
|
||||||
low := uint16(v)
|
low := uint16(v)
|
||||||
return byte(low), byte(low >> 8)
|
return byte(low), byte(low >> 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in sys_windows_386.s and sys_windows_amd64.s
|
||||||
|
func externalthreadhandler()
|
||||||
|
|
||||||
func osinit() {
|
func osinit() {
|
||||||
asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
|
asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
|
||||||
|
|
||||||
@ -173,21 +158,7 @@ func osinit() {
|
|||||||
|
|
||||||
externalthreadhandlerp = funcPC(externalthreadhandler)
|
externalthreadhandlerp = funcPC(externalthreadhandler)
|
||||||
|
|
||||||
major, _ := getVersion()
|
initExceptionHandler()
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
|
||||||
|
|
||||||
@ -482,37 +453,6 @@ func usleep(us uint32) {
|
|||||||
usleep1(10 * us)
|
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 {
|
func ctrlhandler1(_type uint32) uint32 {
|
||||||
var s uint32
|
var s uint32
|
||||||
|
|
||||||
@ -604,35 +544,3 @@ func resetcpuprofiler(hz int32) {
|
|||||||
func memlimit() uintptr {
|
func memlimit() uintptr {
|
||||||
return 0
|
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")
|
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.
|
// Stubs so tests can link correctly. These should never be called.
|
||||||
func open(name *byte, mode, perm int32) int32 {
|
func open(name *byte, mode, perm int32) int32 {
|
||||||
throw("unimplemented")
|
throw("unimplemented")
|
||||||
|
@ -8,6 +8,40 @@ import (
|
|||||||
"unsafe"
|
"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 {
|
func isgoexception(info *exceptionrecord, r *context) bool {
|
||||||
// Only handle exception if executing instructions in Go binary
|
// Only handle exception if executing instructions in Go binary
|
||||||
// (not Windows library code).
|
// (not Windows library code).
|
||||||
@ -16,17 +50,26 @@ func isgoexception(info *exceptionrecord, r *context) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if issigpanic(info.exceptioncode) == 0 {
|
// Go will only handle some exceptions.
|
||||||
|
switch info.exceptioncode {
|
||||||
|
default:
|
||||||
return false
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by sigtramp from Windows VEH handler.
|
// Called by sigtramp from Windows VEH handler.
|
||||||
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
|
// 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).
|
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
|
||||||
|
|
||||||
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
|
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
|
||||||
if !isgoexception(info, r) {
|
if !isgoexception(info, r) {
|
||||||
return _EXCEPTION_CONTINUE_SEARCH
|
return _EXCEPTION_CONTINUE_SEARCH
|
||||||
@ -108,6 +151,51 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
|
|||||||
return 0 // not reached
|
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) {
|
func sigenable(sig uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,3 +204,14 @@ func sigdisable(sig uint32) {
|
|||||||
|
|
||||||
func sigignore(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