uint32 runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { uintptr *sp; switch(info->ExceptionCode) { case EXCEPTION_BREAKPOINT: r->Eip--; // because 8l generates 2 bytes for INT3 return 1; } if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = info->ExceptionCode; gp->sigcode0 = info->ExceptionInformation[0]; gp->sigcode1 = info->ExceptionInformation[1]; gp->sigpc = r->Eip; // Only push runtime·sigpanic if r->eip != 0. // If r->eip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(r->Eip != 0) { sp = (uintptr*)r->Esp; *--sp = r->Eip; r->Esp = (uintptr)sp; } r->Eip = (uintptr)runtime·sigpanic; return 0; } if(runtime·panicking) // traceback already printed runtime·exit(2); runtime·panicking = 1; runtime·printf("Exception %x %p %p\n", info->ExceptionCode, info->ExceptionInformation[0], info->ExceptionInformation[1]); runtime·printf("PC=%x\n", r->Eip); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(r); } runtime·exit(2); return 0; }
bool runtime·isgoexception(ExceptionRecord *info, Context *r) { extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) return false; if(!runtime·issigpanic(info->ExceptionCode)) return false; return true; }
// Called by sigtramp from Windows VEH handler. // Return value signals whether the exception has been handled (-1) // or should be made available to other handlers in the chain (0). uint32 runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { bool crash; uintptr *sp; extern byte text[], etext[]; if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) { // This exception is intended to be caught by debuggers. // There is a not-very-informational message like // "Invalid parameter passed to C runtime function" // sitting at info->ExceptionInformation[0] (a wchar_t*), // with length info->ExceptionInformation[1]. // The default behavior is to ignore this exception, // but somehow returning 0 here (meaning keep going) // makes the program crash instead. Maybe Windows has no // other handler registered? In any event, ignore it. return -1; } // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Rip < (uint64)text || (uint64)etext < r->Rip) return 0; switch(info->ExceptionCode) { case EXCEPTION_BREAKPOINT: // It is unclear whether this is needed, unclear whether it // would work, and unclear how to test it. Leave out for now. // This only handles breakpoint instructions written in the // assembly sources, not breakpoints set by a debugger, and // there are very few of the former. break; } if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break // the unwinding code. gp->sig = info->ExceptionCode; gp->sigcode0 = info->ExceptionInformation[0]; gp->sigcode1 = info->ExceptionInformation[1]; gp->sigpc = r->Rip; // Only push runtime·sigpanic if r->rip != 0. // If r->rip == 0, probably panicked because of a // call to a nil func. Not pushing that onto sp will // make the trace look like a call to runtime·sigpanic instead. // (Otherwise the trace will end at runtime·sigpanic and we // won't get to see who faulted.) if(r->Rip != 0) { sp = (uintptr*)r->Rsp; *--sp = r->Rip; r->Rsp = (uintptr)sp; } r->Rip = (uintptr)runtime·sigpanic; return -1; } if(runtime·panicking) // traceback already printed runtime·exit(2); runtime·panicking = 1; runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip); runtime·printf("PC=%X\n", r->Rip); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { runtime·printf("signal arrived during cgo execution\n"); gp = m->lockedg; } runtime·printf("\n"); if(runtime·gotraceback(&crash)){ runtime·traceback(r->Rip, r->Rsp, 0, gp); runtime·tracebackothers(gp); runtime·dumpregs(r); } if(crash) runtime·crash(); runtime·exit(2); return -1; // not reached }