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 	// Make it look like a call to the signal func.
     75 	// Have to pass arguments out of band since
     76 	// augmenting the stack frame would break
     77 	// the unwinding code.
     78 	gp.sig = info.exceptioncode
     79 	gp.sigcode0 = uintptr(info.exceptioninformation[0])
     80 	gp.sigcode1 = uintptr(info.exceptioninformation[1])
     81 	gp.sigpc = r.ip()
     82 
     83 	// Only push runtimesigpanic if r.ip() != 0.
     84 	// If r.ip() == 0, probably panicked because of a
     85 	// call to a nil func.  Not pushing that onto sp will
     86 	// make the trace look like a call to runtimesigpanic instead.
     87 	// (Otherwise the trace will end at runtimesigpanic and we
     88 	// won't get to see who faulted.)
     89 	if r.ip() != 0 {
     90 		sp := unsafe.Pointer(r.sp())
     91 		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
     92 		*((*uintptr)(sp)) = r.ip()
     93 		r.setsp(uintptr(sp))
     94 	}
     95 	r.setip(funcPC(sigpanic))
     96 	return _EXCEPTION_CONTINUE_EXECUTION
     97 }
     98 
     99 // It seems Windows searches ContinueHandler's list even
    100 // if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
    101 // firstcontinuehandler will stop that search,
    102 // if exceptionhandler did the same earlier.
    103 func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
    104 	if !isgoexception(info, r) {
    105 		return _EXCEPTION_CONTINUE_SEARCH
    106 	}
    107 	return _EXCEPTION_CONTINUE_EXECUTION
    108 }
    109 
    110 var testingWER bool
    111 
    112 // lastcontinuehandler is reached, because runtime cannot handle
    113 // current exception. lastcontinuehandler will print crash info and exit.
    114 func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
    115 	if testingWER {
    116 		return _EXCEPTION_CONTINUE_SEARCH
    117 	}
    118 
    119 	_g_ := getg()
    120 
    121 	if panicking != 0 { // traceback already printed
    122 		exit(2)
    123 	}
    124 	panicking = 1
    125 
    126 	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
    127 
    128 	print("PC=", hex(r.ip()), "\n")
    129 	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
    130 		if iscgo {
    131 			print("signal arrived during external code execution\n")
    132 		}
    133 		gp = _g_.m.lockedg
    134 	}
    135 	print("\n")
    136 
    137 	var docrash bool
    138 	if gotraceback(&docrash) > 0 {
    139 		tracebacktrap(r.ip(), r.sp(), 0, gp)
    140 		tracebackothers(gp)
    141 		dumpregs(r)
    142 	}
    143 
    144 	if docrash {
    145 		crash()
    146 	}
    147 
    148 	exit(2)
    149 	return 0 // not reached
    150 }
    151 
    152 func sigpanic() {
    153 	g := getg()
    154 	if !canpanic(g) {
    155 		throw("unexpected signal during runtime execution")
    156 	}
    157 
    158 	switch uint32(g.sig) {
    159 	case _EXCEPTION_ACCESS_VIOLATION:
    160 		if g.sigcode1 < 0x1000 || g.paniconfault {
    161 			panicmem()
    162 		}
    163 		print("unexpected fault address ", hex(g.sigcode1), "\n")
    164 		throw("fault")
    165 	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
    166 		panicdivide()
    167 	case _EXCEPTION_INT_OVERFLOW:
    168 		panicoverflow()
    169 	case _EXCEPTION_FLT_DENORMAL_OPERAND,
    170 		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
    171 		_EXCEPTION_FLT_INEXACT_RESULT,
    172 		_EXCEPTION_FLT_OVERFLOW,
    173 		_EXCEPTION_FLT_UNDERFLOW:
    174 		panicfloat()
    175 	}
    176 	throw("fault")
    177 }
    178 
    179 var (
    180 	badsignalmsg [100]byte
    181 	badsignallen int32
    182 )
    183 
    184 func setBadSignalMsg() {
    185 	const msg = "runtime: signal received on thread not created by Go.\n"
    186 	for i, c := range msg {
    187 		badsignalmsg[i] = byte(c)
    188 		badsignallen++
    189 	}
    190 }
    191 
    192 // Following are not implemented.
    193 
    194 func initsig() {
    195 }
    196 
    197 func sigenable(sig uint32) {
    198 }
    199 
    200 func sigdisable(sig uint32) {
    201 }
    202 
    203 func sigignore(sig uint32) {
    204 }
    205 
    206 func badsignal2()
    207 
    208 func raisebadsignal(sig int32) {
    209 	badsignal2()
    210 }
    211 
    212 func crash() {
    213 	// TODO: This routine should do whatever is needed
    214 	// to make the Windows program abort/crash as it
    215 	// would if Go was not intercepting signals.
    216 	// On Unix the routine would remove the custom signal
    217 	// handler and then raise a signal (like SIGABRT).
    218 	// Something like that should happen here.
    219 	// It's okay to leave this empty for now: if crash returns
    220 	// the ordinary exit-after-panic happens.
    221 }
    222