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 c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
     42 		// The signal is going to cause a panic.
     43 		// Arrange the stack so that it looks like the point
     44 		// where the signal occurred made a call to the
     45 		// function sigpanic. Then set the PC to sigpanic.
     46 
     47 		// Have to pass arguments out of band since
     48 		// augmenting the stack frame would break
     49 		// the unwinding code.
     50 		gp.sig = sig
     51 		gp.sigcode0 = uintptr(c.sigcode())
     52 		gp.sigcode1 = uintptr(c.fault())
     53 		gp.sigpc = c.sigpc()
     54 
     55 		c.preparePanic(sig, gp)
     56 		return
     57 	}
     58 
     59 	if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
     60 		if sigsend(sig) {
     61 			return
     62 		}
     63 	}
     64 
     65 	if c.sigcode() == _SI_USER && signal_ignored(sig) {
     66 		return
     67 	}
     68 
     69 	if flags&_SigKill != 0 {
     70 		dieFromSignal(sig)
     71 	}
     72 
     73 	if flags&_SigThrow == 0 {
     74 		return
     75 	}
     76 
     77 	_g_.m.throwing = 1
     78 	_g_.m.caughtsig.set(gp)
     79 
     80 	if crashing == 0 {
     81 		startpanic()
     82 	}
     83 
     84 	if sig < uint32(len(sigtable)) {
     85 		print(sigtable[sig].name, "\n")
     86 	} else {
     87 		print("Signal ", sig, "\n")
     88 	}
     89 
     90 	print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
     91 	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
     92 		print("signal arrived during cgo execution\n")
     93 		gp = _g_.m.lockedg
     94 	}
     95 	print("\n")
     96 
     97 	level, _, docrash := gotraceback()
     98 	if level > 0 {
     99 		goroutineheader(gp)
    100 		tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
    101 		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
    102 			// tracebackothers on original m skipped this one; trace it now.
    103 			goroutineheader(_g_.m.curg)
    104 			traceback(^uintptr(0), ^uintptr(0), 0, gp)
    105 		} else if crashing == 0 {
    106 			tracebackothers(gp)
    107 			print("\n")
    108 		}
    109 		dumpregs(c)
    110 	}
    111 
    112 	if docrash {
    113 		crashing++
    114 		if crashing < sched.mcount {
    115 			// There are other m's that need to dump their stacks.
    116 			// Relay SIGQUIT to the next m by sending it to the current process.
    117 			// All m's that have already received SIGQUIT have signal masks blocking
    118 			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
    119 			// When the last m receives the SIGQUIT, it will fall through to the call to
    120 			// crash below. Just in case the relaying gets botched, each m involved in
    121 			// the relay sleeps for 5 seconds and then does the crash/exit itself.
    122 			// In expected operation, the last m has received the SIGQUIT and run
    123 			// crash/exit and the process is gone, all long before any of the
    124 			// 5-second sleeps have finished.
    125 			print("\n-----\n\n")
    126 			raiseproc(_SIGQUIT)
    127 			usleep(5 * 1000 * 1000)
    128 		}
    129 		crash()
    130 	}
    131 
    132 	exit(2)
    133 }
    134