github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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  	"internal/abi"
     9  	"runtime/internal/sys"
    10  	"unsafe"
    11  )
    12  
    13  func disableWER() {
    14  	// do not display Windows Error Reporting dialogue
    15  	const (
    16  		SEM_FAILCRITICALERRORS     = 0x0001
    17  		SEM_NOGPFAULTERRORBOX      = 0x0002
    18  		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
    19  		SEM_NOOPENFILEERRORBOX     = 0x8000
    20  	)
    21  	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
    22  	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
    23  }
    24  
    25  // in sys_windows_386.s and sys_windows_amd64.s
    26  func exceptiontramp()
    27  func firstcontinuetramp()
    28  func lastcontinuetramp()
    29  
    30  func initExceptionHandler() {
    31  	stdcall2(_AddVectoredExceptionHandler, 1, abi.FuncPCABI0(exceptiontramp))
    32  	if _AddVectoredContinueHandler == nil || GOARCH == "386" {
    33  		// use SetUnhandledExceptionFilter for windows-386 or
    34  		// if VectoredContinueHandler is unavailable.
    35  		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
    36  		stdcall1(_SetUnhandledExceptionFilter, abi.FuncPCABI0(lastcontinuetramp))
    37  	} else {
    38  		stdcall2(_AddVectoredContinueHandler, 1, abi.FuncPCABI0(firstcontinuetramp))
    39  		stdcall2(_AddVectoredContinueHandler, 0, abi.FuncPCABI0(lastcontinuetramp))
    40  	}
    41  }
    42  
    43  // isAbort returns true, if context r describes exception raised
    44  // by calling runtime.abort function.
    45  //
    46  //go:nosplit
    47  func isAbort(r *context) bool {
    48  	pc := r.ip()
    49  	if GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm" {
    50  		// In the case of an abort, the exception IP is one byte after
    51  		// the INT3 (this differs from UNIX OSes). Note that on ARM,
    52  		// this means that the exception IP is no longer aligned.
    53  		pc--
    54  	}
    55  	return isAbortPC(pc)
    56  }
    57  
    58  // isgoexception reports whether this exception should be translated
    59  // into a Go panic or throw.
    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  	// Go will only handle some exceptions.
    74  	switch info.exceptioncode {
    75  	default:
    76  		return false
    77  	case _EXCEPTION_ACCESS_VIOLATION:
    78  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
    79  	case _EXCEPTION_INT_OVERFLOW:
    80  	case _EXCEPTION_FLT_DENORMAL_OPERAND:
    81  	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
    82  	case _EXCEPTION_FLT_INEXACT_RESULT:
    83  	case _EXCEPTION_FLT_OVERFLOW:
    84  	case _EXCEPTION_FLT_UNDERFLOW:
    85  	case _EXCEPTION_BREAKPOINT:
    86  	case _EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
    87  	}
    88  	return true
    89  }
    90  
    91  // Called by sigtramp from Windows VEH handler.
    92  // Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
    93  // or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
    94  //
    95  // This is the first entry into Go code for exception handling. This
    96  // is nosplit to avoid growing the stack until we've checked for
    97  // _EXCEPTION_BREAKPOINT, which is raised if we overflow the g0 stack,
    98  //
    99  //go:nosplit
   100  func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
   101  	if !isgoexception(info, r) {
   102  		return _EXCEPTION_CONTINUE_SEARCH
   103  	}
   104  
   105  	if gp.throwsplit || isAbort(r) {
   106  		// We can't safely sigpanic because it may grow the stack.
   107  		// Or this is a call to abort.
   108  		// Don't go through any more of the Windows handler chain.
   109  		// Crash now.
   110  		winthrow(info, r, gp)
   111  	}
   112  
   113  	// After this point, it is safe to grow the stack.
   114  
   115  	// Make it look like a call to the signal func.
   116  	// Have to pass arguments out of band since
   117  	// augmenting the stack frame would break
   118  	// the unwinding code.
   119  	gp.sig = info.exceptioncode
   120  	gp.sigcode0 = info.exceptioninformation[0]
   121  	gp.sigcode1 = info.exceptioninformation[1]
   122  	gp.sigpc = r.ip()
   123  
   124  	// Only push runtime·sigpanic if r.ip() != 0.
   125  	// If r.ip() == 0, probably panicked because of a
   126  	// call to a nil func. Not pushing that onto sp will
   127  	// make the trace look like a call to runtime·sigpanic instead.
   128  	// (Otherwise the trace will end at runtime·sigpanic and we
   129  	// won't get to see who faulted.)
   130  	// Also don't push a sigpanic frame if the faulting PC
   131  	// is the entry of asyncPreempt. In this case, we suspended
   132  	// the thread right between the fault and the exception handler
   133  	// starting to run, and we have pushed an asyncPreempt call.
   134  	// The exception is not from asyncPreempt, so not to push a
   135  	// sigpanic call to make it look like that. Instead, just
   136  	// overwrite the PC. (See issue #35773)
   137  	if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) {
   138  		sp := unsafe.Pointer(r.sp())
   139  		delta := uintptr(sys.StackAlign)
   140  		sp = add(sp, -delta)
   141  		r.set_sp(uintptr(sp))
   142  		if usesLR {
   143  			*((*uintptr)(sp)) = r.lr()
   144  			r.set_lr(r.ip())
   145  		} else {
   146  			*((*uintptr)(sp)) = r.ip()
   147  		}
   148  	}
   149  	r.set_ip(abi.FuncPCABI0(sigpanic0))
   150  	return _EXCEPTION_CONTINUE_EXECUTION
   151  }
   152  
   153  // It seems Windows searches ContinueHandler's list even
   154  // if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
   155  // firstcontinuehandler will stop that search,
   156  // if exceptionhandler did the same earlier.
   157  //
   158  // It is nosplit for the same reason as exceptionhandler.
   159  //
   160  //go:nosplit
   161  func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   162  	if !isgoexception(info, r) {
   163  		return _EXCEPTION_CONTINUE_SEARCH
   164  	}
   165  	return _EXCEPTION_CONTINUE_EXECUTION
   166  }
   167  
   168  var testingWER bool
   169  
   170  // lastcontinuehandler is reached, because runtime cannot handle
   171  // current exception. lastcontinuehandler will print crash info and exit.
   172  //
   173  // It is nosplit for the same reason as exceptionhandler.
   174  //
   175  //go:nosplit
   176  func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   177  	if islibrary || isarchive {
   178  		// Go DLL/archive has been loaded in a non-go program.
   179  		// If the exception does not originate from go, the go runtime
   180  		// should not take responsibility of crashing the process.
   181  		return _EXCEPTION_CONTINUE_SEARCH
   182  	}
   183  	if testingWER {
   184  		return _EXCEPTION_CONTINUE_SEARCH
   185  	}
   186  
   187  	// VEH is called before SEH, but arm64 MSVC DLLs use SEH to trap
   188  	// illegal instructions during runtime initialization to determine
   189  	// CPU features, so if we make it to the last handler and we're
   190  	// arm64 and it's an illegal instruction and this is coming from
   191  	// non-Go code, then assume it's this runtime probing happen, and
   192  	// pass that onward to SEH.
   193  	if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
   194  		(r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
   195  		return _EXCEPTION_CONTINUE_SEARCH
   196  	}
   197  
   198  	winthrow(info, r, gp)
   199  	return 0 // not reached
   200  }
   201  
   202  // Always called on g0. gp is the G where the exception occurred.
   203  //
   204  //go:nosplit
   205  func winthrow(info *exceptionrecord, r *context, gp *g) {
   206  	g0 := getg()
   207  
   208  	if panicking.Load() != 0 { // traceback already printed
   209  		exit(2)
   210  	}
   211  	panicking.Store(1)
   212  
   213  	// In case we're handling a g0 stack overflow, blow away the
   214  	// g0 stack bounds so we have room to print the traceback. If
   215  	// this somehow overflows the stack, the OS will trap it.
   216  	g0.stack.lo = 0
   217  	g0.stackguard0 = g0.stack.lo + _StackGuard
   218  	g0.stackguard1 = g0.stackguard0
   219  
   220  	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
   221  
   222  	print("PC=", hex(r.ip()), "\n")
   223  	if g0.m.incgo && gp == g0.m.g0 && g0.m.curg != nil {
   224  		if iscgo {
   225  			print("signal arrived during external code execution\n")
   226  		}
   227  		gp = g0.m.curg
   228  	}
   229  	print("\n")
   230  
   231  	g0.m.throwing = throwTypeRuntime
   232  	g0.m.caughtsig.set(gp)
   233  
   234  	level, _, docrash := gotraceback()
   235  	if level > 0 {
   236  		tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
   237  		tracebackothers(gp)
   238  		dumpregs(r)
   239  	}
   240  
   241  	if docrash {
   242  		crash()
   243  	}
   244  
   245  	exit(2)
   246  }
   247  
   248  func sigpanic() {
   249  	gp := getg()
   250  	if !canpanic() {
   251  		throw("unexpected signal during runtime execution")
   252  	}
   253  
   254  	switch gp.sig {
   255  	case _EXCEPTION_ACCESS_VIOLATION:
   256  		if gp.sigcode1 < 0x1000 {
   257  			panicmem()
   258  		}
   259  		if gp.paniconfault {
   260  			panicmemAddr(gp.sigcode1)
   261  		}
   262  		if inUserArenaChunk(gp.sigcode1) {
   263  			// We could check that the arena chunk is explicitly set to fault,
   264  			// but the fact that we faulted on accessing it is enough to prove
   265  			// that it is.
   266  			print("accessed data from freed user arena ", hex(gp.sigcode1), "\n")
   267  		} else {
   268  			print("unexpected fault address ", hex(gp.sigcode1), "\n")
   269  		}
   270  		throw("fault")
   271  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   272  		panicdivide()
   273  	case _EXCEPTION_INT_OVERFLOW:
   274  		panicoverflow()
   275  	case _EXCEPTION_FLT_DENORMAL_OPERAND,
   276  		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
   277  		_EXCEPTION_FLT_INEXACT_RESULT,
   278  		_EXCEPTION_FLT_OVERFLOW,
   279  		_EXCEPTION_FLT_UNDERFLOW:
   280  		panicfloat()
   281  	}
   282  	throw("fault")
   283  }
   284  
   285  var (
   286  	badsignalmsg [100]byte
   287  	badsignallen int32
   288  )
   289  
   290  func setBadSignalMsg() {
   291  	const msg = "runtime: signal received on thread not created by Go.\n"
   292  	for i, c := range msg {
   293  		badsignalmsg[i] = byte(c)
   294  		badsignallen++
   295  	}
   296  }
   297  
   298  // Following are not implemented.
   299  
   300  func initsig(preinit bool) {
   301  }
   302  
   303  func sigenable(sig uint32) {
   304  }
   305  
   306  func sigdisable(sig uint32) {
   307  }
   308  
   309  func sigignore(sig uint32) {
   310  }
   311  
   312  func badsignal2()
   313  
   314  func raisebadsignal(sig uint32) {
   315  	badsignal2()
   316  }
   317  
   318  func signame(sig uint32) string {
   319  	return ""
   320  }
   321  
   322  //go:nosplit
   323  func crash() {
   324  	// TODO: This routine should do whatever is needed
   325  	// to make the Windows program abort/crash as it
   326  	// would if Go was not intercepting signals.
   327  	// On Unix the routine would remove the custom signal
   328  	// handler and then raise a signal (like SIGABRT).
   329  	// Something like that should happen here.
   330  	// It's okay to leave this empty for now: if crash returns
   331  	// the ordinary exit-after-panic happens.
   332  }
   333  
   334  // gsignalStack is unused on Windows.
   335  type gsignalStack struct{}