...

Source file src/runtime/signal_windows.go

     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 || 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		if r.ip() != 0 {
   133			sp := unsafe.Pointer(r.sp())
   134			sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
   135			r.set_sp(uintptr(sp))
   136			switch GOARCH {
   137			default:
   138				panic("unsupported architecture")
   139			case "386", "amd64":
   140				*((*uintptr)(sp)) = r.ip()
   141			case "arm":
   142				*((*uintptr)(sp)) = r.lr()
   143				r.set_lr(r.ip())
   144			}
   145		}
   146		r.set_ip(funcPC(sigpanic))
   147		return _EXCEPTION_CONTINUE_EXECUTION
   148	}
   149	
   150	// It seems Windows searches ContinueHandler's list even
   151	// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
   152	// firstcontinuehandler will stop that search,
   153	// if exceptionhandler did the same earlier.
   154	//
   155	// It is nosplit for the same reason as exceptionhandler.
   156	//
   157	//go:nosplit
   158	func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   159		if !isgoexception(info, r) {
   160			return _EXCEPTION_CONTINUE_SEARCH
   161		}
   162		return _EXCEPTION_CONTINUE_EXECUTION
   163	}
   164	
   165	var testingWER bool
   166	
   167	// lastcontinuehandler is reached, because runtime cannot handle
   168	// current exception. lastcontinuehandler will print crash info and exit.
   169	//
   170	// It is nosplit for the same reason as exceptionhandler.
   171	//
   172	//go:nosplit
   173	func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
   174		if testingWER {
   175			return _EXCEPTION_CONTINUE_SEARCH
   176		}
   177	
   178		_g_ := getg()
   179	
   180		if panicking != 0 { // traceback already printed
   181			exit(2)
   182		}
   183		panicking = 1
   184	
   185		// In case we're handling a g0 stack overflow, blow away the
   186		// g0 stack bounds so we have room to print the traceback. If
   187		// this somehow overflows the stack, the OS will trap it.
   188		_g_.stack.lo = 0
   189		_g_.stackguard0 = _g_.stack.lo + _StackGuard
   190		_g_.stackguard1 = _g_.stackguard0
   191	
   192		print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
   193	
   194		print("PC=", hex(r.ip()), "\n")
   195		if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
   196			if iscgo {
   197				print("signal arrived during external code execution\n")
   198			}
   199			gp = _g_.m.lockedg.ptr()
   200		}
   201		print("\n")
   202	
   203		// TODO(jordanrh1): This may be needed for 386/AMD64 as well.
   204		if GOARCH == "arm" {
   205			_g_.m.throwing = 1
   206			_g_.m.caughtsig.set(gp)
   207		}
   208	
   209		level, _, docrash := gotraceback()
   210		if level > 0 {
   211			tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
   212			tracebackothers(gp)
   213			dumpregs(r)
   214		}
   215	
   216		if docrash {
   217			crash()
   218		}
   219	
   220		exit(2)
   221		return 0 // not reached
   222	}
   223	
   224	func sigpanic() {
   225		g := getg()
   226		if !canpanic(g) {
   227			throw("unexpected signal during runtime execution")
   228		}
   229	
   230		switch g.sig {
   231		case _EXCEPTION_ACCESS_VIOLATION:
   232			if g.sigcode1 < 0x1000 || g.paniconfault {
   233				panicmem()
   234			}
   235			print("unexpected fault address ", hex(g.sigcode1), "\n")
   236			throw("fault")
   237		case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   238			panicdivide()
   239		case _EXCEPTION_INT_OVERFLOW:
   240			panicoverflow()
   241		case _EXCEPTION_FLT_DENORMAL_OPERAND,
   242			_EXCEPTION_FLT_DIVIDE_BY_ZERO,
   243			_EXCEPTION_FLT_INEXACT_RESULT,
   244			_EXCEPTION_FLT_OVERFLOW,
   245			_EXCEPTION_FLT_UNDERFLOW:
   246			panicfloat()
   247		}
   248		throw("fault")
   249	}
   250	
   251	var (
   252		badsignalmsg [100]byte
   253		badsignallen int32
   254	)
   255	
   256	func setBadSignalMsg() {
   257		const msg = "runtime: signal received on thread not created by Go.\n"
   258		for i, c := range msg {
   259			badsignalmsg[i] = byte(c)
   260			badsignallen++
   261		}
   262	}
   263	
   264	// Following are not implemented.
   265	
   266	func initsig(preinit bool) {
   267	}
   268	
   269	func sigenable(sig uint32) {
   270	}
   271	
   272	func sigdisable(sig uint32) {
   273	}
   274	
   275	func sigignore(sig uint32) {
   276	}
   277	
   278	func badsignal2()
   279	
   280	func raisebadsignal(sig uint32) {
   281		badsignal2()
   282	}
   283	
   284	func signame(sig uint32) string {
   285		return ""
   286	}
   287	
   288	//go:nosplit
   289	func crash() {
   290		// TODO: This routine should do whatever is needed
   291		// to make the Windows program abort/crash as it
   292		// would if Go was not intercepting signals.
   293		// On Unix the routine would remove the custom signal
   294		// handler and then raise a signal (like SIGABRT).
   295		// Something like that should happen here.
   296		// It's okay to leave this empty for now: if crash returns
   297		// the ordinary exit-after-panic happens.
   298	}
   299	
   300	// gsignalStack is unused on Windows.
   301	type gsignalStack struct{}
   302	

View as plain text