Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 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 amd64 amd64p32 |
| 6 | // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris |
| 7 | |
| 8 | package runtime |
| 9 | |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 10 | import ( |
| 11 | "unsafe" |
| 12 | ) |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 13 | |
| 14 | func dumpregs(c *sigctxt) { |
| 15 | print("rax ", hex(c.rax()), "\n") |
| 16 | print("rbx ", hex(c.rbx()), "\n") |
| 17 | print("rcx ", hex(c.rcx()), "\n") |
| 18 | print("rdx ", hex(c.rdx()), "\n") |
| 19 | print("rdi ", hex(c.rdi()), "\n") |
| 20 | print("rsi ", hex(c.rsi()), "\n") |
| 21 | print("rbp ", hex(c.rbp()), "\n") |
| 22 | print("rsp ", hex(c.rsp()), "\n") |
| 23 | print("r8 ", hex(c.r8()), "\n") |
| 24 | print("r9 ", hex(c.r9()), "\n") |
| 25 | print("r10 ", hex(c.r10()), "\n") |
| 26 | print("r11 ", hex(c.r11()), "\n") |
| 27 | print("r12 ", hex(c.r12()), "\n") |
| 28 | print("r13 ", hex(c.r13()), "\n") |
| 29 | print("r14 ", hex(c.r14()), "\n") |
| 30 | print("r15 ", hex(c.r15()), "\n") |
| 31 | print("rip ", hex(c.rip()), "\n") |
| 32 | print("rflags ", hex(c.rflags()), "\n") |
| 33 | print("cs ", hex(c.cs()), "\n") |
| 34 | print("fs ", hex(c.fs()), "\n") |
| 35 | print("gs ", hex(c.gs()), "\n") |
| 36 | } |
| 37 | |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 38 | var crashing int32 |
| 39 | |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 40 | func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { |
| 41 | _g_ := getg() |
| 42 | c := &sigctxt{info, ctxt} |
| 43 | |
| 44 | if sig == _SIGPROF { |
Matthew Dempsky | 3c8a89d | 2015-02-25 14:41:21 +0900 | [diff] [blame] | 45 | sigprof(uintptr(c.rip()), uintptr(c.rsp()), 0, gp, _g_.m) |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 46 | return |
| 47 | } |
| 48 | |
| 49 | if GOOS == "darwin" { |
| 50 | // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47. |
| 51 | // The hardware delivers a different kind of fault for a malformed address |
| 52 | // than it does for an attempt to access a valid but unmapped address. |
| 53 | // OS X 10.9.2 mishandles the malformed address case, making it look like |
| 54 | // a user-generated signal (like someone ran kill -SEGV ourpid). |
| 55 | // We pass user-generated signals to os/signal, or else ignore them. |
| 56 | // Doing that here - and returning to the faulting code - results in an |
| 57 | // infinite loop. It appears the best we can do is rewrite what the kernel |
| 58 | // delivers into something more like the truth. The address used below |
| 59 | // has very little chance of being the one that caused the fault, but it is |
| 60 | // malformed, it is clearly not a real pointer, and if it does get printed |
| 61 | // in real life, people will probably search for it and find this code. |
| 62 | // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e |
| 63 | // as I type this comment. |
| 64 | if sig == _SIGSEGV && c.sigcode() == _SI_USER { |
| 65 | c.set_sigcode(_SI_USER + 1) |
| 66 | c.set_sigaddr(0xb01dfacedebac1e) |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | flags := int32(_SigThrow) |
| 71 | if sig < uint32(len(sigtable)) { |
| 72 | flags = sigtable[sig].flags |
| 73 | } |
| 74 | if c.sigcode() != _SI_USER && flags&_SigPanic != 0 { |
| 75 | // Make it look like a call to the signal func. |
| 76 | // Have to pass arguments out of band since |
| 77 | // augmenting the stack frame would break |
| 78 | // the unwinding code. |
| 79 | gp.sig = sig |
| 80 | gp.sigcode0 = uintptr(c.sigcode()) |
| 81 | gp.sigcode1 = uintptr(c.sigaddr()) |
| 82 | gp.sigpc = uintptr(c.rip()) |
| 83 | |
| 84 | if GOOS == "darwin" { |
| 85 | // Work around Leopard bug that doesn't set FPE_INTDIV. |
| 86 | // Look at instruction to see if it is a divide. |
| 87 | // Not necessary in Snow Leopard (si_code will be != 0). |
| 88 | if sig == _SIGFPE && gp.sigcode0 == 0 { |
| 89 | pc := (*[4]byte)(unsafe.Pointer(gp.sigpc)) |
| 90 | i := 0 |
| 91 | if pc[i]&0xF0 == 0x40 { // 64-bit REX prefix |
| 92 | i++ |
| 93 | } else if pc[i] == 0x66 { // 16-bit instruction prefix |
| 94 | i++ |
| 95 | } |
| 96 | if pc[i] == 0xF6 || pc[i] == 0xF7 { |
| 97 | gp.sigcode0 = _FPE_INTDIV |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | // Only push runtime.sigpanic if rip != 0. |
| 103 | // If rip == 0, probably panicked because of a |
| 104 | // call to a nil func. Not pushing that onto sp will |
| 105 | // make the trace look like a call to runtime.sigpanic instead. |
| 106 | // (Otherwise the trace will end at runtime.sigpanic and we |
| 107 | // won't get to see who faulted.) |
| 108 | if c.rip() != 0 { |
| 109 | sp := c.rsp() |
| 110 | if regSize > ptrSize { |
| 111 | sp -= ptrSize |
| 112 | *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 |
| 113 | } |
| 114 | sp -= ptrSize |
| 115 | *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(c.rip()) |
| 116 | c.set_rsp(sp) |
| 117 | } |
| 118 | c.set_rip(uint64(funcPC(sigpanic))) |
| 119 | return |
| 120 | } |
| 121 | |
| 122 | if c.sigcode() == _SI_USER || flags&_SigNotify != 0 { |
| 123 | if sigsend(sig) { |
| 124 | return |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | if flags&_SigKill != 0 { |
| 129 | exit(2) |
| 130 | } |
| 131 | |
| 132 | if flags&_SigThrow == 0 { |
| 133 | return |
| 134 | } |
| 135 | |
| 136 | _g_.m.throwing = 1 |
| 137 | _g_.m.caughtsig = gp |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 138 | |
| 139 | if crashing == 0 { |
| 140 | startpanic() |
| 141 | } |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 142 | |
| 143 | if sig < uint32(len(sigtable)) { |
| 144 | print(sigtable[sig].name, "\n") |
| 145 | } else { |
| 146 | print("Signal ", sig, "\n") |
| 147 | } |
| 148 | |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 149 | print("PC=", hex(c.rip()), " m=", _g_.m.id, "\n") |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 150 | if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { |
| 151 | print("signal arrived during cgo execution\n") |
| 152 | gp = _g_.m.lockedg |
| 153 | } |
| 154 | print("\n") |
| 155 | |
| 156 | var docrash bool |
| 157 | if gotraceback(&docrash) > 0 { |
| 158 | goroutineheader(gp) |
| 159 | tracebacktrap(uintptr(c.rip()), uintptr(c.rsp()), 0, gp) |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 160 | if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning { |
| 161 | // tracebackothers on original m skipped this one; trace it now. |
| 162 | goroutineheader(_g_.m.curg) |
| 163 | traceback(^uintptr(0), ^uintptr(0), 0, gp) |
| 164 | } else if crashing == 0 { |
| 165 | tracebackothers(gp) |
| 166 | print("\n") |
| 167 | } |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 168 | dumpregs(c) |
| 169 | } |
| 170 | |
| 171 | if docrash { |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 172 | // TODO(rsc): Implement raiseproc on other systems |
Matthew Dempsky | 636de7a | 2015-01-14 13:30:34 -0800 | [diff] [blame] | 173 | // and then add to this if condition. |
| 174 | if GOOS == "darwin" || GOOS == "linux" { |
Russ Cox | 5bfed7c | 2015-01-14 11:18:24 -0500 | [diff] [blame] | 175 | crashing++ |
| 176 | if crashing < sched.mcount { |
| 177 | // There are other m's that need to dump their stacks. |
| 178 | // Relay SIGQUIT to the next m by sending it to the current process. |
| 179 | // All m's that have already received SIGQUIT have signal masks blocking |
| 180 | // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet. |
| 181 | // When the last m receives the SIGQUIT, it will fall through to the call to |
| 182 | // crash below. Just in case the relaying gets botched, each m involved in |
| 183 | // the relay sleeps for 5 seconds and then does the crash/exit itself. |
| 184 | // In expected operation, the last m has received the SIGQUIT and run |
| 185 | // crash/exit and the process is gone, all long before any of the |
| 186 | // 5-second sleeps have finished. |
| 187 | print("\n-----\n\n") |
| 188 | raiseproc(_SIGQUIT) |
| 189 | usleep(5 * 1000 * 1000) |
| 190 | } |
| 191 | } |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 192 | crash() |
| 193 | } |
| 194 | |
| 195 | exit(2) |
| 196 | } |