rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/runtime/signal_windows.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import (
     8  	"unsafe"
     9  )
    10  
    11  func disableWER() {
    12  	// do not display Windows Error Reporting dialogue
    13  	const (
    14  		SEM_FAILCRITICALERRORS     = 0x0001
    15  		SEM_NOGPFAULTERRORBOX      = 0x0002
    16  		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
    17  		SEM_NOOPENFILEERRORBOX     = 0x8000
    18  	)
    19  	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
    20  	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
    21  }
    22  
    23  // in sys_windows_386.s and sys_windows_amd64.s
    24  func exceptiontramp()
    25  func firstcontinuetramp()
    26  func lastcontinuetramp()
    27  
    28  func initExceptionHandler() {
    29  	major, _ := getVersion()
    30  	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
    31  	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
    32  		// use SetUnhandledExceptionFilter for windows-386 or
    33  		// if VectoredContinueHandler is unavailable or
    34  		// if running windows-amd64 v5. V5 appears to fail to
    35  		// call the continue handlers if windows error reporting dialog
    36  		// is disabled.
    37  		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
    38  		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
    39  	} else {
    40  		stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
    41  		stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
    42  	}
    43  }
    44  
    45  func isgoexception(info *exceptionrecord, r *context) bool {
    46  	// Only handle exception if executing instructions in Go binary
    47  	// (not Windows library code).
    48  	// TODO(mwhudson): needs to loop to support shared libs
    49  	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
    50  		return false
    51  	}
    52  
    53  	// Go will only handle some exceptions.
    54  	switch info.exceptioncode {
    55  	default:
    56  		return false
    57  	case _EXCEPTION_ACCESS_VIOLATION:
    58  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
    59  	case _EXCEPTION_INT_OVERFLOW:
    60  	case _EXCEPTION_FLT_DENORMAL_OPERAND:
    61  	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
    62  	case _EXCEPTION_FLT_INEXACT_RESULT:
    63  	case _EXCEPTION_FLT_OVERFLOW:
    64  	case _EXCEPTION_FLT_UNDERFLOW:
    65  	case _EXCEPTION_BREAKPOINT:
    66  	}
    67  	return true
    68  }
    69  
    70  // Called by sigtramp from Windows VEH handler.
    71  // Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
    72  // or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
    73  func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
    74  	if !isgoexception(info, r) {
    75  		return _EXCEPTION_CONTINUE_SEARCH
    76  	}
    77  
    78  	// Make it look like a call to the signal func.
    79  	// Have to pass arguments out of band since
    80  	// augmenting the stack frame would break
    81  	// the unwinding code.
    82  	gp.sig = info.exceptioncode
    83  	gp.sigcode0 = uintptr(info.exceptioninformation[0])
    84  	gp.sigcode1 = uintptr(info.exceptioninformation[1])
    85  	gp.sigpc = r.ip()
    86  
    87  	// Only push runtime·sigpanic if r.ip() != 0.
    88  	// If r.ip() == 0, probably panicked because of a
    89  	// call to a nil func.  Not pushing that onto sp will
    90  	// make the trace look like a call to runtime·sigpanic instead.
    91  	// (Otherwise the trace will end at runtime·sigpanic and we
    92  	// won't get to see who faulted.)
    93  	if r.ip() != 0 {
    94  		sp := unsafe.Pointer(r.sp())
    95  		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
    96  		*((*uintptr)(sp)) = r.ip()
    97  		r.setsp(uintptr(sp))
    98  	}
    99  	r.setip(funcPC(sigpanic))
   100  	return _EXCEPTION_CONTINUE_EXECUTION
   101  }
   102  
   103  // It seems Windows searches ContinueHandler's list even
   104  // if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
   105  // firstcontinuehandler will stop that search,
   106  // if exceptionhandler did the same earlier.
   107  func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   108  	if !isgoexception(info, r) {
   109  		return _EXCEPTION_CONTINUE_SEARCH
   110  	}
   111  	return _EXCEPTION_CONTINUE_EXECUTION
   112  }
   113  
   114  var testingWER bool
   115  
   116  // lastcontinuehandler is reached, because runtime cannot handle
   117  // current exception. lastcontinuehandler will print crash info and exit.
   118  func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   119  	if testingWER {
   120  		return _EXCEPTION_CONTINUE_SEARCH
   121  	}
   122  
   123  	_g_ := getg()
   124  
   125  	if panicking != 0 { // traceback already printed
   126  		exit(2)
   127  	}
   128  	panicking = 1
   129  
   130  	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
   131  
   132  	print("PC=", hex(r.ip()), "\n")
   133  	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
   134  		print("signal arrived during cgo execution\n")
   135  		gp = _g_.m.lockedg
   136  	}
   137  	print("\n")
   138  
   139  	var docrash bool
   140  	if gotraceback(&docrash) > 0 {
   141  		tracebacktrap(r.ip(), r.sp(), 0, gp)
   142  		tracebackothers(gp)
   143  		dumpregs(r)
   144  	}
   145  
   146  	if docrash {
   147  		crash()
   148  	}
   149  
   150  	exit(2)
   151  	return 0 // not reached
   152  }
   153  
   154  func sigpanic() {
   155  	g := getg()
   156  	if !canpanic(g) {
   157  		throw("unexpected signal during runtime execution")
   158  	}
   159  
   160  	switch uint32(g.sig) {
   161  	case _EXCEPTION_ACCESS_VIOLATION:
   162  		if g.sigcode1 < 0x1000 || g.paniconfault {
   163  			panicmem()
   164  		}
   165  		print("unexpected fault address ", hex(g.sigcode1), "\n")
   166  		throw("fault")
   167  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   168  		panicdivide()
   169  	case _EXCEPTION_INT_OVERFLOW:
   170  		panicoverflow()
   171  	case _EXCEPTION_FLT_DENORMAL_OPERAND,
   172  		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
   173  		_EXCEPTION_FLT_INEXACT_RESULT,
   174  		_EXCEPTION_FLT_OVERFLOW,
   175  		_EXCEPTION_FLT_UNDERFLOW:
   176  		panicfloat()
   177  	}
   178  	throw("fault")
   179  }
   180  
   181  var (
   182  	badsignalmsg [100]byte
   183  	badsignallen int32
   184  )
   185  
   186  func setBadSignalMsg() {
   187  	const msg = "runtime: signal received on thread not created by Go.\n"
   188  	for i, c := range msg {
   189  		badsignalmsg[i] = byte(c)
   190  		badsignallen++
   191  	}
   192  }
   193  
   194  // Following are not implemented.
   195  
   196  func initsig() {
   197  }
   198  
   199  func sigenable(sig uint32) {
   200  }
   201  
   202  func sigdisable(sig uint32) {
   203  }
   204  
   205  func sigignore(sig uint32) {
   206  }
   207  
   208  func crash() {
   209  	// TODO: This routine should do whatever is needed
   210  	// to make the Windows program abort/crash as it
   211  	// would if Go was not intercepting signals.
   212  	// On Unix the routine would remove the custom signal
   213  	// handler and then raise a signal (like SIGABRT).
   214  	// Something like that should happen here.
   215  	// It's okay to leave this empty for now: if crash returns
   216  	// the ordinary exit-after-panic happens.
   217  }