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