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