github.com/aloncn/graphics-go@v0.0.1/src/runtime/signal_amd64x.go (about)

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