aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2016-01-06 23:00:08 -0500
committerRuss Cox <rsc@golang.org>2016-01-08 15:33:48 +0000
commit331a6055ab8785e77bd1331355d209bd7da2ae26 (patch)
tree28ee7cc0781fb7460e26ca04b5254d7ff7474dd3 /src
parent6da608206c222c280078264f02135ffaa4e1aa26 (diff)
downloadgo-331a6055ab8785e77bd1331355d209bd7da2ae26.tar.xz
runtime: fix up OS X kernel bug sending user-generated SIGTRAP
OS X unconditionally sets si_code = TRAP_BRKPT when sending SIGTRAP, even if it was generated by kill -TRAP and not a breakpoint. Correct the si_code by looking to see if the PC is after a breakpoint. For #12906. Change-Id: I998c2499f7f12b338e607282a325b045f1f4f690 Reviewed-on: https://go-review.googlesource.com/18347 Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/runtime/signal_darwin.go2
-rw-r--r--src/runtime/signal_darwin_386.go22
-rw-r--r--src/runtime/signal_darwin_amd64.go22
-rw-r--r--src/runtime/signal_darwin_arm.go21
-rw-r--r--src/runtime/signal_darwin_arm64.go21
5 files changed, 88 insertions, 0 deletions
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
index 4a26f3eb08..542169c9f8 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -85,6 +85,8 @@ func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Poi
}
setg(g.m.gsignal)
+ c := &sigctxt{info, ctx}
+ c.fixsigcode(sig)
sighandler(sig, info, ctx, g)
setg(g)
sigreturn(ctx, infostyle)
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
index 302b3aafc9..7f7c22ad18 100644
--- a/src/runtime/signal_darwin_386.go
+++ b/src/runtime/signal_darwin_386.go
@@ -32,3 +32,25 @@ func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x }
+
+func (c *sigctxt) fixsigcode(sig uint32) {
+ switch sig {
+ case _SIGTRAP:
+ // OS X sets c.sigcode() == TRAP_BRKPT unconditionally for all SIGTRAPs,
+ // leaving no way to distinguish a breakpoint-induced SIGTRAP
+ // from an asynchronous signal SIGTRAP.
+ // They all look breakpoint-induced by default.
+ // Try looking at the code to see if it's a breakpoint.
+ // The assumption is that we're very unlikely to get an
+ // asynchronous SIGTRAP at just the moment that the
+ // PC started to point at unmapped memory.
+ pc := uintptr(c.eip())
+ // OS X will leave the pc just after the INT 3 instruction.
+ // INT 3 is usually 1 byte, but there is a 2-byte form.
+ code := (*[2]byte)(unsafe.Pointer(pc - 2))
+ if code[1] != 0xCC && (code[0] != 0xCD || code[1] != 3) {
+ // SIGTRAP on something other than INT 3.
+ c.set_sigcode(_SI_USER)
+ }
+ }
+}
diff --git a/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
index dbf044814c..c9ac293b63 100644
--- a/src/runtime/signal_darwin_amd64.go
+++ b/src/runtime/signal_darwin_amd64.go
@@ -40,3 +40,25 @@ func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x }
func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x }
func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
+
+func (c *sigctxt) fixsigcode(sig uint32) {
+ switch sig {
+ case _SIGTRAP:
+ // OS X sets c.sigcode() == TRAP_BRKPT unconditionally for all SIGTRAPs,
+ // leaving no way to distinguish a breakpoint-induced SIGTRAP
+ // from an asynchronous signal SIGTRAP.
+ // They all look breakpoint-induced by default.
+ // Try looking at the code to see if it's a breakpoint.
+ // The assumption is that we're very unlikely to get an
+ // asynchronous SIGTRAP at just the moment that the
+ // PC started to point at unmapped memory.
+ pc := uintptr(c.rip())
+ // OS X will leave the pc just after the INT 3 instruction.
+ // INT 3 is usually 1 byte, but there is a 2-byte form.
+ code := (*[2]byte)(unsafe.Pointer(pc - 2))
+ if code[1] != 0xCC && (code[0] != 0xCD || code[1] != 3) {
+ // SIGTRAP on something other than INT 3.
+ c.set_sigcode(_SI_USER)
+ }
+ }
+}
diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
index 0f10971931..24c5f5abf6 100644
--- a/src/runtime/signal_darwin_arm.go
+++ b/src/runtime/signal_darwin_arm.go
@@ -42,3 +42,24 @@ func (c *sigctxt) set_r10(x uint32) { c.regs().r[10] = x }
func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x }
+
+func (c *sigctxt) fixsigcode(sig uint32) {
+ switch sig {
+ case _SIGTRAP:
+ // OS X sets c.sigcode() == TRAP_BRKPT unconditionally for all SIGTRAPs,
+ // leaving no way to distinguish a breakpoint-induced SIGTRAP
+ // from an asynchronous signal SIGTRAP.
+ // They all look breakpoint-induced by default.
+ // Try looking at the code to see if it's a breakpoint.
+ // The assumption is that we're very unlikely to get an
+ // asynchronous SIGTRAP at just the moment that the
+ // PC started to point at unmapped memory.
+ pc := uintptr(c.pc())
+ // OS X will leave the pc just after the instruction.
+ code := (*uint32)(unsafe.Pointer(pc - 4))
+ if *code != 0xe7f001f0 {
+ // SIGTRAP on something other than breakpoint.
+ c.set_sigcode(_SI_USER)
+ }
+ }
+}
diff --git a/src/runtime/signal_darwin_arm64.go b/src/runtime/signal_darwin_arm64.go
index 2df4229626..8be0f4f9dc 100644
--- a/src/runtime/signal_darwin_arm64.go
+++ b/src/runtime/signal_darwin_arm64.go
@@ -58,3 +58,24 @@ func (c *sigctxt) set_r28(x uint64) { c.regs().x[28] = x }
func (c *sigctxt) set_sigaddr(x uint64) {
c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x)))
}
+
+func (c *sigctxt) fixsigcode(sig uint32) {
+ switch sig {
+ case _SIGTRAP:
+ // OS X sets c.sigcode() == TRAP_BRKPT unconditionally for all SIGTRAPs,
+ // leaving no way to distinguish a breakpoint-induced SIGTRAP
+ // from an asynchronous signal SIGTRAP.
+ // They all look breakpoint-induced by default.
+ // Try looking at the code to see if it's a breakpoint.
+ // The assumption is that we're very unlikely to get an
+ // asynchronous SIGTRAP at just the moment that the
+ // PC started to point at unmapped memory.
+ pc := uintptr(c.pc())
+ // OS X will leave the pc just after the instruction.
+ code := (*uint32)(unsafe.Pointer(pc - 4))
+ if *code != 0xd4200000 {
+ // SIGTRAP on something other than breakpoint.
+ c.set_sigcode(_SI_USER)
+ }
+ }
+}