mirror of
https://github.com/golang/go
synced 2024-11-19 15:14:45 -07:00
0def0f2e99
The implementation of runtime.abort on arm64 currently branches to address 0, which results in a signal from PC 0, rather than from runtime.abort, so the runtime fails to recognize it as an abort. Fix runtime.abort on arm64 to read from address 0 like what other architectures do and recognize this in the signal handler. Should fix the linux/arm64 build. Change-Id: I960ab630daaeadc9190287604d4d8337b1ea3853 Reviewed-on: https://go-review.googlesource.com/99895 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
240 lines
6.3 KiB
Go
240 lines
6.3 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
func disableWER() {
|
|
// do not display Windows Error Reporting dialogue
|
|
const (
|
|
SEM_FAILCRITICALERRORS = 0x0001
|
|
SEM_NOGPFAULTERRORBOX = 0x0002
|
|
SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
|
|
SEM_NOOPENFILEERRORBOX = 0x8000
|
|
)
|
|
errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
|
|
stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
|
|
}
|
|
|
|
// in sys_windows_386.s and sys_windows_amd64.s
|
|
func exceptiontramp()
|
|
func firstcontinuetramp()
|
|
func lastcontinuetramp()
|
|
|
|
func initExceptionHandler() {
|
|
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
|
|
if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
|
|
// use SetUnhandledExceptionFilter for windows-386 or
|
|
// if VectoredContinueHandler is unavailable.
|
|
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
|
|
stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
|
|
} else {
|
|
stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
|
|
stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
|
|
}
|
|
}
|
|
|
|
func isgoexception(info *exceptionrecord, r *context) bool {
|
|
// Only handle exception if executing instructions in Go binary
|
|
// (not Windows library code).
|
|
// TODO(mwhudson): needs to loop to support shared libs
|
|
if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
|
|
return false
|
|
}
|
|
|
|
if isAbortPC(r.ip()) {
|
|
// Never turn abort into a panic.
|
|
return false
|
|
}
|
|
|
|
// Go will only handle some exceptions.
|
|
switch info.exceptioncode {
|
|
default:
|
|
return false
|
|
case _EXCEPTION_ACCESS_VIOLATION:
|
|
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
|
case _EXCEPTION_INT_OVERFLOW:
|
|
case _EXCEPTION_FLT_DENORMAL_OPERAND:
|
|
case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
|
case _EXCEPTION_FLT_INEXACT_RESULT:
|
|
case _EXCEPTION_FLT_OVERFLOW:
|
|
case _EXCEPTION_FLT_UNDERFLOW:
|
|
case _EXCEPTION_BREAKPOINT:
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Called by sigtramp from Windows VEH handler.
|
|
// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
|
|
// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
|
|
func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
|
|
if !isgoexception(info, r) {
|
|
return _EXCEPTION_CONTINUE_SEARCH
|
|
}
|
|
|
|
if gp.throwsplit {
|
|
// We can't safely sigpanic because it may grow the
|
|
// stack. Let it fall through.
|
|
return _EXCEPTION_CONTINUE_SEARCH
|
|
}
|
|
|
|
// 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 = uintptr(info.exceptioninformation[0])
|
|
gp.sigcode1 = uintptr(info.exceptioninformation[1])
|
|
gp.sigpc = r.ip()
|
|
|
|
// Only push runtime·sigpanic if r.ip() != 0.
|
|
// If r.ip() == 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.ip() != 0 {
|
|
sp := unsafe.Pointer(r.sp())
|
|
sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
|
|
*((*uintptr)(sp)) = r.ip()
|
|
r.setsp(uintptr(sp))
|
|
}
|
|
r.setip(funcPC(sigpanic))
|
|
return _EXCEPTION_CONTINUE_EXECUTION
|
|
}
|
|
|
|
// It seems Windows searches ContinueHandler's list even
|
|
// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
|
|
// firstcontinuehandler will stop that search,
|
|
// if exceptionhandler did the same earlier.
|
|
func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
|
|
if !isgoexception(info, r) {
|
|
return _EXCEPTION_CONTINUE_SEARCH
|
|
}
|
|
return _EXCEPTION_CONTINUE_EXECUTION
|
|
}
|
|
|
|
var testingWER bool
|
|
|
|
// lastcontinuehandler is reached, because runtime cannot handle
|
|
// current exception. lastcontinuehandler will print crash info and exit.
|
|
func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
|
|
if testingWER {
|
|
return _EXCEPTION_CONTINUE_SEARCH
|
|
}
|
|
|
|
_g_ := getg()
|
|
|
|
if panicking != 0 { // traceback already printed
|
|
exit(2)
|
|
}
|
|
panicking = 1
|
|
|
|
print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
|
|
|
|
print("PC=", hex(r.ip()), "\n")
|
|
if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
|
|
if iscgo {
|
|
print("signal arrived during external code execution\n")
|
|
}
|
|
gp = _g_.m.lockedg.ptr()
|
|
}
|
|
print("\n")
|
|
|
|
level, _, docrash := gotraceback()
|
|
if level > 0 {
|
|
tracebacktrap(r.ip(), r.sp(), 0, gp)
|
|
tracebackothers(gp)
|
|
dumpregs(r)
|
|
}
|
|
|
|
if docrash {
|
|
crash()
|
|
}
|
|
|
|
exit(2)
|
|
return 0 // not reached
|
|
}
|
|
|
|
func sigpanic() {
|
|
g := getg()
|
|
if !canpanic(g) {
|
|
throw("unexpected signal during runtime execution")
|
|
}
|
|
|
|
switch g.sig {
|
|
case _EXCEPTION_ACCESS_VIOLATION:
|
|
if g.sigcode1 < 0x1000 || g.paniconfault {
|
|
panicmem()
|
|
}
|
|
print("unexpected fault address ", hex(g.sigcode1), "\n")
|
|
throw("fault")
|
|
case _EXCEPTION_INT_DIVIDE_BY_ZERO:
|
|
panicdivide()
|
|
case _EXCEPTION_INT_OVERFLOW:
|
|
panicoverflow()
|
|
case _EXCEPTION_FLT_DENORMAL_OPERAND,
|
|
_EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
|
_EXCEPTION_FLT_INEXACT_RESULT,
|
|
_EXCEPTION_FLT_OVERFLOW,
|
|
_EXCEPTION_FLT_UNDERFLOW:
|
|
panicfloat()
|
|
}
|
|
throw("fault")
|
|
}
|
|
|
|
var (
|
|
badsignalmsg [100]byte
|
|
badsignallen int32
|
|
)
|
|
|
|
func setBadSignalMsg() {
|
|
const msg = "runtime: signal received on thread not created by Go.\n"
|
|
for i, c := range msg {
|
|
badsignalmsg[i] = byte(c)
|
|
badsignallen++
|
|
}
|
|
}
|
|
|
|
// Following are not implemented.
|
|
|
|
func initsig(preinit bool) {
|
|
}
|
|
|
|
func sigenable(sig uint32) {
|
|
}
|
|
|
|
func sigdisable(sig uint32) {
|
|
}
|
|
|
|
func sigignore(sig uint32) {
|
|
}
|
|
|
|
func badsignal2()
|
|
|
|
func raisebadsignal(sig uint32) {
|
|
badsignal2()
|
|
}
|
|
|
|
func signame(sig uint32) string {
|
|
return ""
|
|
}
|
|
|
|
func crash() {
|
|
// TODO: This routine should do whatever is needed
|
|
// to make the Windows program abort/crash as it
|
|
// would if Go was not intercepting signals.
|
|
// On Unix the routine would remove the custom signal
|
|
// handler and then raise a signal (like SIGABRT).
|
|
// Something like that should happen here.
|
|
// It's okay to leave this empty for now: if crash returns
|
|
// the ordinary exit-after-panic happens.
|
|
}
|
|
|
|
// gsignalStack is unused on Windows.
|
|
type gsignalStack struct{}
|