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