From d1af6bed847291599985e85a8fbf207b6f0342a6 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 13 Apr 2015 12:02:44 +1000 Subject: [PATCH] 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 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/os1_windows.go | 100 ++------------------------------ src/runtime/os_windows.go | 27 --------- src/runtime/signal_windows.go | 105 +++++++++++++++++++++++++++++++++- 3 files changed, 106 insertions(+), 126 deletions(-) diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index 508c4951e8..1ab6ed1437 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -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. -} diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 744dc66ccc..31df064959 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -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") diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index 110d37c4df..da8a1c5801 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -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. +}