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