]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix up OS X kernel bug sending user-generated SIGTRAP
authorRuss Cox <rsc@golang.org>
Thu, 7 Jan 2016 04:00:08 +0000 (23:00 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 8 Jan 2016 15:33:48 +0000 (15:33 +0000)
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>
src/runtime/signal_darwin.go
src/runtime/signal_darwin_386.go
src/runtime/signal_darwin_amd64.go
src/runtime/signal_darwin_arm.go
src/runtime/signal_darwin_arm64.go

index 4a26f3eb08a97ab5b6eee72402ac8da0675411c1..542169c9f8b8986887227fe184d88e840c7121a4 100644 (file)
@@ -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)
index 302b3aafc9d9fe392f0916aeec534df9b22c1199..7f7c22ad1801781550562fe1f8e42ae5a9258d94 100644 (file)
@@ -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)
+               }
+       }
+}
index dbf044814ce63eefde2bf061249c52108745dd37..c9ac293b637d7383834a4f92855a52263e5a2b0a 100644 (file)
@@ -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)
+               }
+       }
+}
index 0f1097193159b04fa19cc20263e1680afb31dbd5..24c5f5abf6071eb4953e43278b7c81c78bfe4d27 100644 (file)
@@ -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)
+               }
+       }
+}
index 2df42296269b886078f11685b0dd2fbec550a360..8be0f4f9dcaf9c8828d9bd77906fd2f3ddca3d80 100644 (file)
@@ -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)
+               }
+       }
+}