...
Run Format

Source file src/runtime/signal_windows.go

Documentation: runtime

     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  // isgoexception returns true if this exception should be translated
    42  // into a Go panic.
    43  //
    44  // It is nosplit to avoid growing the stack in case we're aborting
    45  // because of a stack overflow.
    46  //
    47  //go:nosplit
    48  func isgoexception(info *exceptionrecord, r *context) bool {
    49  	// Only handle exception if executing instructions in Go binary
    50  	// (not Windows library code).
    51  	// TODO(mwhudson): needs to loop to support shared libs
    52  	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
    53  		return false
    54  	}
    55  
    56  	// In the case of an abort, the exception IP is one byte after
    57  	// the INT3 (this differs from UNIX OSes).
    58  	if isAbortPC(r.ip() - 1) {
    59  		// Never turn abort into a panic.
    60  		return false
    61  	}
    62  
    63  	// Go will only handle some exceptions.
    64  	switch info.exceptioncode {
    65  	default:
    66  		return false
    67  	case _EXCEPTION_ACCESS_VIOLATION:
    68  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
    69  	case _EXCEPTION_INT_OVERFLOW:
    70  	case _EXCEPTION_FLT_DENORMAL_OPERAND:
    71  	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
    72  	case _EXCEPTION_FLT_INEXACT_RESULT:
    73  	case _EXCEPTION_FLT_OVERFLOW:
    74  	case _EXCEPTION_FLT_UNDERFLOW:
    75  	case _EXCEPTION_BREAKPOINT:
    76  	}
    77  	return true
    78  }
    79  
    80  // Called by sigtramp from Windows VEH handler.
    81  // Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
    82  // or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
    83  //
    84  // This is the first entry into Go code for exception handling. This
    85  // is nosplit to avoid growing the stack until we've checked for
    86  // _EXCEPTION_BREAKPOINT, which is raised if we overflow the g0 stack,
    87  //
    88  //go:nosplit
    89  func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
    90  	if !isgoexception(info, r) {
    91  		return _EXCEPTION_CONTINUE_SEARCH
    92  	}
    93  
    94  	// After this point, it is safe to grow the stack.
    95  
    96  	if gp.throwsplit {
    97  		// We can't safely sigpanic because it may grow the
    98  		// stack. Let it fall through.
    99  		return _EXCEPTION_CONTINUE_SEARCH
   100  	}
   101  
   102  	// Make it look like a call to the signal func.
   103  	// Have to pass arguments out of band since
   104  	// augmenting the stack frame would break
   105  	// the unwinding code.
   106  	gp.sig = info.exceptioncode
   107  	gp.sigcode0 = uintptr(info.exceptioninformation[0])
   108  	gp.sigcode1 = uintptr(info.exceptioninformation[1])
   109  	gp.sigpc = r.ip()
   110  
   111  	// Only push runtime·sigpanic if r.ip() != 0.
   112  	// If r.ip() == 0, probably panicked because of a
   113  	// call to a nil func. Not pushing that onto sp will
   114  	// make the trace look like a call to runtime·sigpanic instead.
   115  	// (Otherwise the trace will end at runtime·sigpanic and we
   116  	// won't get to see who faulted.)
   117  	if r.ip() != 0 {
   118  		sp := unsafe.Pointer(r.sp())
   119  		sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
   120  		*((*uintptr)(sp)) = r.ip()
   121  		r.setsp(uintptr(sp))
   122  	}
   123  	r.setip(funcPC(sigpanic))
   124  	return _EXCEPTION_CONTINUE_EXECUTION
   125  }
   126  
   127  // It seems Windows searches ContinueHandler's list even
   128  // if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
   129  // firstcontinuehandler will stop that search,
   130  // if exceptionhandler did the same earlier.
   131  //
   132  // It is nosplit for the same reason as exceptionhandler.
   133  //
   134  //go:nosplit
   135  func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   136  	if !isgoexception(info, r) {
   137  		return _EXCEPTION_CONTINUE_SEARCH
   138  	}
   139  	return _EXCEPTION_CONTINUE_EXECUTION
   140  }
   141  
   142  var testingWER bool
   143  
   144  // lastcontinuehandler is reached, because runtime cannot handle
   145  // current exception. lastcontinuehandler will print crash info and exit.
   146  //
   147  // It is nosplit for the same reason as exceptionhandler.
   148  //
   149  //go:nosplit
   150  func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   151  	if testingWER {
   152  		return _EXCEPTION_CONTINUE_SEARCH
   153  	}
   154  
   155  	_g_ := getg()
   156  
   157  	if panicking != 0 { // traceback already printed
   158  		exit(2)
   159  	}
   160  	panicking = 1
   161  
   162  	// In case we're handling a g0 stack overflow, blow away the
   163  	// g0 stack bounds so we have room to print the traceback. If
   164  	// this somehow overflows the stack, the OS will trap it.
   165  	_g_.stack.lo = 0
   166  	_g_.stackguard0 = _g_.stack.lo + _StackGuard
   167  	_g_.stackguard1 = _g_.stackguard0
   168  
   169  	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
   170  
   171  	print("PC=", hex(r.ip()), "\n")
   172  	if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
   173  		if iscgo {
   174  			print("signal arrived during external code execution\n")
   175  		}
   176  		gp = _g_.m.lockedg.ptr()
   177  	}
   178  	print("\n")
   179  
   180  	level, _, docrash := gotraceback()
   181  	if level > 0 {
   182  		tracebacktrap(r.ip(), r.sp(), 0, gp)
   183  		tracebackothers(gp)
   184  		dumpregs(r)
   185  	}
   186  
   187  	if docrash {
   188  		crash()
   189  	}
   190  
   191  	exit(2)
   192  	return 0 // not reached
   193  }
   194  
   195  func sigpanic() {
   196  	g := getg()
   197  	if !canpanic(g) {
   198  		throw("unexpected signal during runtime execution")
   199  	}
   200  
   201  	switch g.sig {
   202  	case _EXCEPTION_ACCESS_VIOLATION:
   203  		if g.sigcode1 < 0x1000 || g.paniconfault {
   204  			panicmem()
   205  		}
   206  		print("unexpected fault address ", hex(g.sigcode1), "\n")
   207  		throw("fault")
   208  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   209  		panicdivide()
   210  	case _EXCEPTION_INT_OVERFLOW:
   211  		panicoverflow()
   212  	case _EXCEPTION_FLT_DENORMAL_OPERAND,
   213  		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
   214  		_EXCEPTION_FLT_INEXACT_RESULT,
   215  		_EXCEPTION_FLT_OVERFLOW,
   216  		_EXCEPTION_FLT_UNDERFLOW:
   217  		panicfloat()
   218  	}
   219  	throw("fault")
   220  }
   221  
   222  var (
   223  	badsignalmsg [100]byte
   224  	badsignallen int32
   225  )
   226  
   227  func setBadSignalMsg() {
   228  	const msg = "runtime: signal received on thread not created by Go.\n"
   229  	for i, c := range msg {
   230  		badsignalmsg[i] = byte(c)
   231  		badsignallen++
   232  	}
   233  }
   234  
   235  // Following are not implemented.
   236  
   237  func initsig(preinit bool) {
   238  }
   239  
   240  func sigenable(sig uint32) {
   241  }
   242  
   243  func sigdisable(sig uint32) {
   244  }
   245  
   246  func sigignore(sig uint32) {
   247  }
   248  
   249  func badsignal2()
   250  
   251  func raisebadsignal(sig uint32) {
   252  	badsignal2()
   253  }
   254  
   255  func signame(sig uint32) string {
   256  	return ""
   257  }
   258  
   259  //go:nosplit
   260  func crash() {
   261  	// TODO: This routine should do whatever is needed
   262  	// to make the Windows program abort/crash as it
   263  	// would if Go was not intercepting signals.
   264  	// On Unix the routine would remove the custom signal
   265  	// handler and then raise a signal (like SIGABRT).
   266  	// Something like that should happen here.
   267  	// It's okay to leave this empty for now: if crash returns
   268  	// the ordinary exit-after-panic happens.
   269  }
   270  
   271  // gsignalStack is unused on Windows.
   272  type gsignalStack struct{}
   273  

View as plain text