...

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  	"internal/abi"
     9  	"runtime/internal/sys"
    10  	"unsafe"
    11  )
    12  
    13  const (
    14  	_SEM_FAILCRITICALERRORS = 0x0001
    15  	_SEM_NOGPFAULTERRORBOX  = 0x0002
    16  	_SEM_NOOPENFILEERRORBOX = 0x8000
    17  
    18  	_WER_FAULT_REPORTING_NO_UI = 0x0020
    19  )
    20  
    21  func preventErrorDialogs() {
    22  	errormode := stdcall0(_GetErrorMode)
    23  	stdcall1(_SetErrorMode, errormode|_SEM_FAILCRITICALERRORS|_SEM_NOGPFAULTERRORBOX|_SEM_NOOPENFILEERRORBOX)
    24  
    25  	// Disable WER fault reporting UI.
    26  	// Do this even if WER is disabled as a whole,
    27  	// as WER might be enabled later with setTraceback("wer")
    28  	// and we still want the fault reporting UI to be disabled if this happens.
    29  	var werflags uintptr
    30  	stdcall2(_WerGetFlags, currentProcess, uintptr(unsafe.Pointer(&werflags)))
    31  	stdcall1(_WerSetFlags, werflags|_WER_FAULT_REPORTING_NO_UI)
    32  }
    33  
    34  // enableWER re-enables Windows error reporting without fault reporting UI.
    35  func enableWER() {
    36  	// re-enable Windows Error Reporting
    37  	errormode := stdcall0(_GetErrorMode)
    38  	if errormode&_SEM_NOGPFAULTERRORBOX != 0 {
    39  		stdcall1(_SetErrorMode, errormode^_SEM_NOGPFAULTERRORBOX)
    40  	}
    41  }
    42  
    43  // in sys_windows_386.s, sys_windows_amd64.s, sys_windows_arm.s, and sys_windows_arm64.s
    44  func exceptiontramp()
    45  func firstcontinuetramp()
    46  func lastcontinuetramp()
    47  func sehtramp()
    48  func sigresume()
    49  
    50  func initExceptionHandler() {
    51  	stdcall2(_AddVectoredExceptionHandler, 1, abi.FuncPCABI0(exceptiontramp))
    52  	if GOARCH == "386" {
    53  		// use SetUnhandledExceptionFilter for windows-386.
    54  		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
    55  		stdcall1(_SetUnhandledExceptionFilter, abi.FuncPCABI0(lastcontinuetramp))
    56  	} else {
    57  		stdcall2(_AddVectoredContinueHandler, 1, abi.FuncPCABI0(firstcontinuetramp))
    58  		stdcall2(_AddVectoredContinueHandler, 0, abi.FuncPCABI0(lastcontinuetramp))
    59  	}
    60  }
    61  
    62  // isAbort returns true, if context r describes exception raised
    63  // by calling runtime.abort function.
    64  //
    65  //go:nosplit
    66  func isAbort(r *context) bool {
    67  	pc := r.ip()
    68  	if GOARCH == "386" || GOARCH == "amd64" || GOARCH == "arm" {
    69  		// In the case of an abort, the exception IP is one byte after
    70  		// the INT3 (this differs from UNIX OSes). Note that on ARM,
    71  		// this means that the exception IP is no longer aligned.
    72  		pc--
    73  	}
    74  	return isAbortPC(pc)
    75  }
    76  
    77  // isgoexception reports whether this exception should be translated
    78  // into a Go panic or throw.
    79  //
    80  // It is nosplit to avoid growing the stack in case we're aborting
    81  // because of a stack overflow.
    82  //
    83  //go:nosplit
    84  func isgoexception(info *exceptionrecord, r *context) bool {
    85  	// Only handle exception if executing instructions in Go binary
    86  	// (not Windows library code).
    87  	// TODO(mwhudson): needs to loop to support shared libs
    88  	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
    89  		return false
    90  	}
    91  
    92  	// Go will only handle some exceptions.
    93  	switch info.exceptioncode {
    94  	default:
    95  		return false
    96  	case _EXCEPTION_ACCESS_VIOLATION:
    97  	case _EXCEPTION_IN_PAGE_ERROR:
    98  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
    99  	case _EXCEPTION_INT_OVERFLOW:
   100  	case _EXCEPTION_FLT_DENORMAL_OPERAND:
   101  	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
   102  	case _EXCEPTION_FLT_INEXACT_RESULT:
   103  	case _EXCEPTION_FLT_OVERFLOW:
   104  	case _EXCEPTION_FLT_UNDERFLOW:
   105  	case _EXCEPTION_BREAKPOINT:
   106  	case _EXCEPTION_ILLEGAL_INSTRUCTION: // breakpoint arrives this way on arm64
   107  	}
   108  	return true
   109  }
   110  
   111  const (
   112  	callbackVEH = iota
   113  	callbackFirstVCH
   114  	callbackLastVCH
   115  )
   116  
   117  // sigFetchGSafe is like getg() but without panicking
   118  // when TLS is not set.
   119  // Only implemented on windows/386, which is the only
   120  // arch that loads TLS when calling getg(). Others
   121  // use a dedicated register.
   122  func sigFetchGSafe() *g
   123  
   124  func sigFetchG() *g {
   125  	if GOARCH == "386" {
   126  		return sigFetchGSafe()
   127  	}
   128  	return getg()
   129  }
   130  
   131  // sigtrampgo is called from the exception handler function, sigtramp,
   132  // written in assembly code.
   133  // Return EXCEPTION_CONTINUE_EXECUTION if the exception is handled,
   134  // else return EXCEPTION_CONTINUE_SEARCH.
   135  //
   136  // It is nosplit for the same reason as exceptionhandler.
   137  //
   138  //go:nosplit
   139  func sigtrampgo(ep *exceptionpointers, kind int) int32 {
   140  	gp := sigFetchG()
   141  	if gp == nil {
   142  		return _EXCEPTION_CONTINUE_SEARCH
   143  	}
   144  
   145  	var fn func(info *exceptionrecord, r *context, gp *g) int32
   146  	switch kind {
   147  	case callbackVEH:
   148  		fn = exceptionhandler
   149  	case callbackFirstVCH:
   150  		fn = firstcontinuehandler
   151  	case callbackLastVCH:
   152  		fn = lastcontinuehandler
   153  	default:
   154  		throw("unknown sigtramp callback")
   155  	}
   156  
   157  	// Check if we are running on g0 stack, and if we are,
   158  	// call fn directly instead of creating the closure.
   159  	// for the systemstack argument.
   160  	//
   161  	// A closure can't be marked as nosplit, so it might
   162  	// call morestack if we are at the g0 stack limit.
   163  	// If that happens, the runtime will call abort
   164  	// and end up in sigtrampgo again.
   165  	// TODO: revisit this workaround if/when closures
   166  	// can be compiled as nosplit.
   167  	//
   168  	// Note that this scenario should only occur on
   169  	// TestG0StackOverflow. Any other occurrence should
   170  	// be treated as a bug.
   171  	var ret int32
   172  	if gp != gp.m.g0 {
   173  		systemstack(func() {
   174  			ret = fn(ep.record, ep.context, gp)
   175  		})
   176  	} else {
   177  		ret = fn(ep.record, ep.context, gp)
   178  	}
   179  	if ret == _EXCEPTION_CONTINUE_SEARCH {
   180  		return ret
   181  	}
   182  
   183  	// Check if we need to set up the control flow guard workaround.
   184  	// On Windows, the stack pointer in the context must lie within
   185  	// system stack limits when we resume from exception.
   186  	// Store the resume SP and PC in alternate registers
   187  	// and return to sigresume on the g0 stack.
   188  	// sigresume makes no use of the stack at all,
   189  	// loading SP from RX and jumping to RY, being RX and RY two scratch registers.
   190  	// Note that blindly smashing RX and RY is only safe because we know sigpanic
   191  	// will not actually return to the original frame, so the registers
   192  	// are effectively dead. But this does mean we can't use the
   193  	// same mechanism for async preemption.
   194  	if ep.context.ip() == abi.FuncPCABI0(sigresume) {
   195  		// sigresume has already been set up by a previous exception.
   196  		return ret
   197  	}
   198  	prepareContextForSigResume(ep.context)
   199  	ep.context.set_sp(gp.m.g0.sched.sp)
   200  	ep.context.set_ip(abi.FuncPCABI0(sigresume))
   201  	return ret
   202  }
   203  
   204  // Called by sigtramp from Windows VEH handler.
   205  // Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
   206  // or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
   207  //
   208  // This is nosplit to avoid growing the stack until we've checked for
   209  // _EXCEPTION_BREAKPOINT, which is raised by abort() if we overflow the g0 stack.
   210  //
   211  //go:nosplit
   212  func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
   213  	if !isgoexception(info, r) {
   214  		return _EXCEPTION_CONTINUE_SEARCH
   215  	}
   216  
   217  	if gp.throwsplit || isAbort(r) {
   218  		// We can't safely sigpanic because it may grow the stack.
   219  		// Or this is a call to abort.
   220  		// Don't go through any more of the Windows handler chain.
   221  		// Crash now.
   222  		winthrow(info, r, gp)
   223  	}
   224  
   225  	// After this point, it is safe to grow the stack.
   226  
   227  	// Make it look like a call to the signal func.
   228  	// Have to pass arguments out of band since
   229  	// augmenting the stack frame would break
   230  	// the unwinding code.
   231  	gp.sig = info.exceptioncode
   232  	gp.sigcode0 = info.exceptioninformation[0]
   233  	gp.sigcode1 = info.exceptioninformation[1]
   234  	gp.sigpc = r.ip()
   235  
   236  	// Only push runtime·sigpanic if r.ip() != 0.
   237  	// If r.ip() == 0, probably panicked because of a
   238  	// call to a nil func. Not pushing that onto sp will
   239  	// make the trace look like a call to runtime·sigpanic instead.
   240  	// (Otherwise the trace will end at runtime·sigpanic and we
   241  	// won't get to see who faulted.)
   242  	// Also don't push a sigpanic frame if the faulting PC
   243  	// is the entry of asyncPreempt. In this case, we suspended
   244  	// the thread right between the fault and the exception handler
   245  	// starting to run, and we have pushed an asyncPreempt call.
   246  	// The exception is not from asyncPreempt, so not to push a
   247  	// sigpanic call to make it look like that. Instead, just
   248  	// overwrite the PC. (See issue #35773)
   249  	if r.ip() != 0 && r.ip() != abi.FuncPCABI0(asyncPreempt) {
   250  		sp := unsafe.Pointer(r.sp())
   251  		delta := uintptr(sys.StackAlign)
   252  		sp = add(sp, -delta)
   253  		r.set_sp(uintptr(sp))
   254  		if usesLR {
   255  			*((*uintptr)(sp)) = r.lr()
   256  			r.set_lr(r.ip())
   257  		} else {
   258  			*((*uintptr)(sp)) = r.ip()
   259  		}
   260  	}
   261  	r.set_ip(abi.FuncPCABI0(sigpanic0))
   262  	return _EXCEPTION_CONTINUE_EXECUTION
   263  }
   264  
   265  // sehhandler is reached as part of the SEH chain.
   266  //
   267  // It is nosplit for the same reason as exceptionhandler.
   268  //
   269  //go:nosplit
   270  func sehhandler(_ *exceptionrecord, _ uint64, _ *context, dctxt *_DISPATCHER_CONTEXT) int32 {
   271  	g0 := getg()
   272  	if g0 == nil || g0.m.curg == nil {
   273  		// No g available, nothing to do here.
   274  		return _EXCEPTION_CONTINUE_SEARCH_SEH
   275  	}
   276  	// The Windows SEH machinery will unwind the stack until it finds
   277  	// a frame with a handler for the exception or until the frame is
   278  	// outside the stack boundaries, in which case it will call the
   279  	// UnhandledExceptionFilter. Unfortunately, it doesn't know about
   280  	// the goroutine stack, so it will stop unwinding when it reaches the
   281  	// first frame not running in g0. As a result, neither non-Go exceptions
   282  	// handlers higher up the stack nor UnhandledExceptionFilter will be called.
   283  	//
   284  	// To work around this, manually unwind the stack until the top of the goroutine
   285  	// stack is reached, and then pass the control back to Windows.
   286  	gp := g0.m.curg
   287  	ctxt := dctxt.ctx()
   288  	var base, sp uintptr
   289  	for {
   290  		entry := stdcall3(_RtlLookupFunctionEntry, ctxt.ip(), uintptr(unsafe.Pointer(&base)), 0)
   291  		if entry == 0 {
   292  			break
   293  		}
   294  		stdcall8(_RtlVirtualUnwind, 0, base, ctxt.ip(), entry, uintptr(unsafe.Pointer(ctxt)), 0, uintptr(unsafe.Pointer(&sp)), 0)
   295  		if sp < gp.stack.lo || gp.stack.hi <= sp {
   296  			break
   297  		}
   298  	}
   299  	return _EXCEPTION_CONTINUE_SEARCH_SEH
   300  }
   301  
   302  // It seems Windows searches ContinueHandler's list even
   303  // if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
   304  // firstcontinuehandler will stop that search,
   305  // if exceptionhandler did the same earlier.
   306  //
   307  // It is nosplit for the same reason as exceptionhandler.
   308  //
   309  //go:nosplit
   310  func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   311  	if !isgoexception(info, r) {
   312  		return _EXCEPTION_CONTINUE_SEARCH
   313  	}
   314  	return _EXCEPTION_CONTINUE_EXECUTION
   315  }
   316  
   317  // lastcontinuehandler is reached, because runtime cannot handle
   318  // current exception. lastcontinuehandler will print crash info and exit.
   319  //
   320  // It is nosplit for the same reason as exceptionhandler.
   321  //
   322  //go:nosplit
   323  func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   324  	if islibrary || isarchive {
   325  		// Go DLL/archive has been loaded in a non-go program.
   326  		// If the exception does not originate from go, the go runtime
   327  		// should not take responsibility of crashing the process.
   328  		return _EXCEPTION_CONTINUE_SEARCH
   329  	}
   330  
   331  	// VEH is called before SEH, but arm64 MSVC DLLs use SEH to trap
   332  	// illegal instructions during runtime initialization to determine
   333  	// CPU features, so if we make it to the last handler and we're
   334  	// arm64 and it's an illegal instruction and this is coming from
   335  	// non-Go code, then assume it's this runtime probing happen, and
   336  	// pass that onward to SEH.
   337  	if GOARCH == "arm64" && info.exceptioncode == _EXCEPTION_ILLEGAL_INSTRUCTION &&
   338  		(r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip()) {
   339  		return _EXCEPTION_CONTINUE_SEARCH
   340  	}
   341  
   342  	winthrow(info, r, gp)
   343  	return 0 // not reached
   344  }
   345  
   346  // Always called on g0. gp is the G where the exception occurred.
   347  //
   348  //go:nosplit
   349  func winthrow(info *exceptionrecord, r *context, gp *g) {
   350  	g0 := getg()
   351  
   352  	if panicking.Load() != 0 { // traceback already printed
   353  		exit(2)
   354  	}
   355  	panicking.Store(1)
   356  
   357  	// In case we're handling a g0 stack overflow, blow away the
   358  	// g0 stack bounds so we have room to print the traceback. If
   359  	// this somehow overflows the stack, the OS will trap it.
   360  	g0.stack.lo = 0
   361  	g0.stackguard0 = g0.stack.lo + stackGuard
   362  	g0.stackguard1 = g0.stackguard0
   363  
   364  	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
   365  
   366  	print("PC=", hex(r.ip()), "\n")
   367  	if g0.m.incgo && gp == g0.m.g0 && g0.m.curg != nil {
   368  		if iscgo {
   369  			print("signal arrived during external code execution\n")
   370  		}
   371  		gp = g0.m.curg
   372  	}
   373  	print("\n")
   374  
   375  	g0.m.throwing = throwTypeRuntime
   376  	g0.m.caughtsig.set(gp)
   377  
   378  	level, _, docrash := gotraceback()
   379  	if level > 0 {
   380  		tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
   381  		tracebackothers(gp)
   382  		dumpregs(r)
   383  	}
   384  
   385  	if docrash {
   386  		dieFromException(info, r)
   387  	}
   388  
   389  	exit(2)
   390  }
   391  
   392  func sigpanic() {
   393  	gp := getg()
   394  	if !canpanic() {
   395  		throw("unexpected signal during runtime execution")
   396  	}
   397  
   398  	switch gp.sig {
   399  	case _EXCEPTION_ACCESS_VIOLATION, _EXCEPTION_IN_PAGE_ERROR:
   400  		if gp.sigcode1 < 0x1000 {
   401  			panicmem()
   402  		}
   403  		if gp.paniconfault {
   404  			panicmemAddr(gp.sigcode1)
   405  		}
   406  		if inUserArenaChunk(gp.sigcode1) {
   407  			// We could check that the arena chunk is explicitly set to fault,
   408  			// but the fact that we faulted on accessing it is enough to prove
   409  			// that it is.
   410  			print("accessed data from freed user arena ", hex(gp.sigcode1), "\n")
   411  		} else {
   412  			print("unexpected fault address ", hex(gp.sigcode1), "\n")
   413  		}
   414  		throw("fault")
   415  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   416  		panicdivide()
   417  	case _EXCEPTION_INT_OVERFLOW:
   418  		panicoverflow()
   419  	case _EXCEPTION_FLT_DENORMAL_OPERAND,
   420  		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
   421  		_EXCEPTION_FLT_INEXACT_RESULT,
   422  		_EXCEPTION_FLT_OVERFLOW,
   423  		_EXCEPTION_FLT_UNDERFLOW:
   424  		panicfloat()
   425  	}
   426  	throw("fault")
   427  }
   428  
   429  // Following are not implemented.
   430  
   431  func initsig(preinit bool) {
   432  }
   433  
   434  func sigenable(sig uint32) {
   435  }
   436  
   437  func sigdisable(sig uint32) {
   438  }
   439  
   440  func sigignore(sig uint32) {
   441  }
   442  
   443  func signame(sig uint32) string {
   444  	return ""
   445  }
   446  
   447  //go:nosplit
   448  func crash() {
   449  	dieFromException(nil, nil)
   450  }
   451  
   452  // dieFromException raises an exception that bypasses all exception handlers.
   453  // This provides the expected exit status for the shell.
   454  //
   455  //go:nosplit
   456  func dieFromException(info *exceptionrecord, r *context) {
   457  	if info == nil {
   458  		gp := getg()
   459  		if gp.sig != 0 {
   460  			// Try to reconstruct an exception record from
   461  			// the exception information stored in gp.
   462  			info = &exceptionrecord{
   463  				exceptionaddress: gp.sigpc,
   464  				exceptioncode:    gp.sig,
   465  				numberparameters: 2,
   466  			}
   467  			info.exceptioninformation[0] = gp.sigcode0
   468  			info.exceptioninformation[1] = gp.sigcode1
   469  		} else {
   470  			// By default, a failing Go application exits with exit code 2.
   471  			// Use this value when gp does not contain exception info.
   472  			info = &exceptionrecord{
   473  				exceptioncode: 2,
   474  			}
   475  		}
   476  	}
   477  	const FAIL_FAST_GENERATE_EXCEPTION_ADDRESS = 0x1
   478  	stdcall3(_RaiseFailFastException, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(r)), FAIL_FAST_GENERATE_EXCEPTION_ADDRESS)
   479  }
   480  
   481  // gsignalStack is unused on Windows.
   482  type gsignalStack struct{}
   483  

View as plain text