Home | History | Annotate | Download | only in runtime
      1 // Copyright 2013 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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
      6 
      7 package runtime
      8 
      9 import (
     10 	"unsafe"
     11 )
     12 
     13 // crashing is the number of m's we have waited for when implementing
     14 // GOTRACEBACK=crash when a signal is received.
     15 var crashing int32
     16 
     17 // sighandler is invoked when a signal occurs. The global g will be
     18 // set to a gsignal goroutine and we will be running on the alternate
     19 // signal stack. The parameter g will be the value of the global g
     20 // when the signal occurred. The sig, info, and ctxt parameters are
     21 // from the system signal handler: they are the parameters passed when
     22 // the SA is passed to the sigaction system call.
     23 //
     24 // The garbage collector may have stopped the world, so write barriers
     25 // are not allowed.
     26 //
     27 //go:nowritebarrierrec
     28 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
     29 	_g_ := getg()
     30 	c := &sigctxt{info, ctxt}
     31 
     32 	if sig == _SIGPROF {
     33 		sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
     34 		return
     35 	}
     36 
     37 	flags := int32(_SigThrow)
     38 	if sig < uint32(len(sigtable)) {
     39 		flags = sigtable[sig].flags
     40 	}
     41 	if flags&_SigPanic != 0 && gp.throwsplit {
     42 		// We can't safely sigpanic because it may grow the
     43 		// stack. Abort in the signal handler instead.
     44 		flags = (flags &^ _SigPanic) | _SigThrow
     45 	}
     46 	if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
     47 		// The signal is going to cause a panic.
     48 		// Arrange the stack so that it looks like the point
     49 		// where the signal occurred made a call to the
     50 		// function sigpanic. Then set the PC to sigpanic.
     51 
     52 		// Have to pass arguments out of band since
     53 		// augmenting the stack frame would break
     54 		// the unwinding code.
     55 		gp.sig = sig
     56 		gp.sigcode0 = uintptr(c.sigcode())
     57 		gp.sigcode1 = uintptr(c.fault())
     58 		gp.sigpc = c.sigpc()
     59 
     60 		c.preparePanic(sig, gp)
     61 		return
     62 	}
     63 
     64 	if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
     65 		if sigsend(sig) {
     66 			return
     67 		}
     68 	}
     69 
     70 	if c.sigcode() == _SI_USER && signal_ignored(sig) {
     71 		return
     72 	}
     73 
     74 	if flags&_SigKill != 0 {
     75 		dieFromSignal(sig)
     76 	}
     77 
     78 	if flags&_SigThrow == 0 {
     79 		return
     80 	}
     81 
     82 	_g_.m.throwing = 1
     83 	_g_.m.caughtsig.set(gp)
     84 
     85 	if crashing == 0 {
     86 		startpanic()
     87 	}
     88 
     89 	if sig < uint32(len(sigtable)) {
     90 		print(sigtable[sig].name, "\n")
     91 	} else {
     92 		print("Signal ", sig, "\n")
     93 	}
     94 
     95 	print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
     96 	if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
     97 		print("signal arrived during cgo execution\n")
     98 		gp = _g_.m.lockedg.ptr()
     99 	}
    100 	print("\n")
    101 
    102 	level, _, docrash := gotraceback()
    103 	if level > 0 {
    104 		goroutineheader(gp)
    105 		tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
    106 		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
    107 			// tracebackothers on original m skipped this one; trace it now.
    108 			goroutineheader(_g_.m.curg)
    109 			traceback(^uintptr(0), ^uintptr(0), 0, _g_.m.curg)
    110 		} else if crashing == 0 {
    111 			tracebackothers(gp)
    112 			print("\n")
    113 		}
    114 		dumpregs(c)
    115 	}
    116 
    117 	if docrash {
    118 		crashing++
    119 		if crashing < mcount()-int32(extraMCount) {
    120 			// There are other m's that need to dump their stacks.
    121 			// Relay SIGQUIT to the next m by sending it to the current process.
    122 			// All m's that have already received SIGQUIT have signal masks blocking
    123 			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
    124 			// When the last m receives the SIGQUIT, it will fall through to the call to
    125 			// crash below. Just in case the relaying gets botched, each m involved in
    126 			// the relay sleeps for 5 seconds and then does the crash/exit itself.
    127 			// In expected operation, the last m has received the SIGQUIT and run
    128 			// crash/exit and the process is gone, all long before any of the
    129 			// 5-second sleeps have finished.
    130 			print("\n-----\n\n")
    131 			raiseproc(_SIGQUIT)
    132 			usleep(5 * 1000 * 1000)
    133 		}
    134 		crash()
    135 	}
    136 
    137 	exit(2)
    138 }
    139