1 // Copyright 2009 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 6 7 package runtime 8 9 import "unsafe" 10 11 func dumpregs(c *sigctxt) { 12 print("trap ", hex(c.trap()), "\n") 13 print("error ", hex(c.error()), "\n") 14 print("oldmask ", hex(c.oldmask()), "\n") 15 print("r0 ", hex(c.r0()), "\n") 16 print("r1 ", hex(c.r1()), "\n") 17 print("r2 ", hex(c.r2()), "\n") 18 print("r3 ", hex(c.r3()), "\n") 19 print("r4 ", hex(c.r4()), "\n") 20 print("r5 ", hex(c.r5()), "\n") 21 print("r6 ", hex(c.r6()), "\n") 22 print("r7 ", hex(c.r7()), "\n") 23 print("r8 ", hex(c.r8()), "\n") 24 print("r9 ", hex(c.r9()), "\n") 25 print("r10 ", hex(c.r10()), "\n") 26 print("fp ", hex(c.fp()), "\n") 27 print("ip ", hex(c.ip()), "\n") 28 print("sp ", hex(c.sp()), "\n") 29 print("lr ", hex(c.lr()), "\n") 30 print("pc ", hex(c.pc()), "\n") 31 print("cpsr ", hex(c.cpsr()), "\n") 32 print("fault ", hex(c.fault()), "\n") 33 } 34 35 var crashing int32 36 37 // May run during STW, so write barriers are not allowed. 38 //go:nowritebarrier 39 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { 40 _g_ := getg() 41 c := &sigctxt{info, ctxt} 42 43 if sig == _SIGPROF { 44 sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp, _g_.m) 45 return 46 } 47 48 flags := int32(_SigThrow) 49 if sig < uint32(len(sigtable)) { 50 flags = sigtable[sig].flags 51 } 52 if c.sigcode() != _SI_USER && flags&_SigPanic != 0 { 53 // Make it look like a call to the signal func. 54 // Have to pass arguments out of band since 55 // augmenting the stack frame would break 56 // the unwinding code. 57 gp.sig = sig 58 gp.sigcode0 = uintptr(c.sigcode()) 59 gp.sigcode1 = uintptr(c.fault()) 60 gp.sigpc = uintptr(c.pc()) 61 62 // We arrange lr, and pc to pretend the panicking 63 // function calls sigpanic directly. 64 // Always save LR to stack so that panics in leaf 65 // functions are correctly handled. This smashes 66 // the stack frame but we're not going back there 67 // anyway. 68 sp := c.sp() - 4 69 c.set_sp(sp) 70 *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr() 71 72 pc := uintptr(gp.sigpc) 73 74 // If we don't recognize the PC as code 75 // but we do recognize the link register as code, 76 // then assume this was a call to non-code and treat like 77 // pc == 0, to make unwinding show the context. 78 if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil { 79 pc = 0 80 } 81 82 // Don't bother saving PC if it's zero, which is 83 // probably a call to a nil func: the old link register 84 // is more useful in the stack trace. 85 if pc != 0 { 86 c.set_lr(uint32(pc)) 87 } 88 89 // In case we are panicking from external C code 90 c.set_r10(uint32(uintptr(unsafe.Pointer(gp)))) 91 c.set_pc(uint32(funcPC(sigpanic))) 92 return 93 } 94 95 if c.sigcode() == _SI_USER || flags&_SigNotify != 0 { 96 if sigsend(sig) { 97 return 98 } 99 } 100 101 if flags&_SigKill != 0 { 102 exit(2) 103 } 104 105 if flags&_SigThrow == 0 { 106 return 107 } 108 109 _g_.m.throwing = 1 110 _g_.m.caughtsig.set(gp) 111 112 if crashing == 0 { 113 startpanic() 114 } 115 116 if sig < uint32(len(sigtable)) { 117 print(sigtable[sig].name, "\n") 118 } else { 119 print("Signal ", sig, "\n") 120 } 121 122 print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n") 123 if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { 124 print("signal arrived during cgo execution\n") 125 gp = _g_.m.lockedg 126 } 127 print("\n") 128 129 var docrash bool 130 if gotraceback(&docrash) > 0 { 131 goroutineheader(gp) 132 tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp) 133 if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning { 134 // tracebackothers on original m skipped this one; trace it now. 135 goroutineheader(_g_.m.curg) 136 traceback(^uintptr(0), ^uintptr(0), 0, gp) 137 } else if crashing == 0 { 138 tracebackothers(gp) 139 print("\n") 140 } 141 dumpregs(c) 142 } 143 144 if docrash { 145 crashing++ 146 if crashing < sched.mcount { 147 // There are other m's that need to dump their stacks. 148 // Relay SIGQUIT to the next m by sending it to the current process. 149 // All m's that have already received SIGQUIT have signal masks blocking 150 // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet. 151 // When the last m receives the SIGQUIT, it will fall through to the call to 152 // crash below. Just in case the relaying gets botched, each m involved in 153 // the relay sleeps for 5 seconds and then does the crash/exit itself. 154 // In expected operation, the last m has received the SIGQUIT and run 155 // crash/exit and the process is gone, all long before any of the 156 // 5-second sleeps have finished. 157 print("\n-----\n\n") 158 raiseproc(_SIGQUIT) 159 usleep(5 * 1000 * 1000) 160 } 161 crash() 162 } 163 164 exit(2) 165 } 166