From 2d031dc559a720ec2c1939848a2e5de2782acd5a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 14 Oct 2019 19:28:58 -0400 Subject: [PATCH] runtime: support for injecting calls at signals on x86 This adds a sigctxt.pushCall method that pushes a call at the signaled site. We'll use this to inject asynchronous preemptions and in some places we use it to clean up preparePanic. For the moment this only works on 386 and amd64. We stub it out on other platforms and will avoid calling the stubbed version. For #10958, #24543. Change-Id: I49e0e853f935d32dd67a70c6cafbae44ee68af8e Reviewed-on: https://go-review.googlesource.com/c/go/+/201758 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/runtime/signal_386.go | 25 ++++++++++++++++--------- src/runtime/signal_amd64.go | 26 +++++++++++++++++--------- src/runtime/signal_arm.go | 6 ++++++ src/runtime/signal_arm64.go | 6 ++++++ src/runtime/signal_linux_s390x.go | 6 ++++++ src/runtime/signal_mips64x.go | 6 ++++++ src/runtime/signal_mipsx.go | 6 ++++++ src/runtime/signal_ppc64x.go | 6 ++++++ 8 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go index ef97979796..2670dc850d 100644 --- a/src/runtime/signal_386.go +++ b/src/runtime/signal_386.go @@ -57,14 +57,21 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { sp := uintptr(c.esp()) if shouldPushSigpanic(gp, pc, *(*uintptr)(unsafe.Pointer(sp))) { - // Make it look like the faulting PC called sigpanic. - if sys.RegSize > sys.PtrSize { - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = 0 - } - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = pc - c.set_esp(uint32(sp)) + c.pushCall(funcPC(sigpanic)) + } else { + // Not safe to push the call. Just clobber the frame. + c.set_eip(uint32(funcPC(sigpanic))) } - c.set_eip(uint32(funcPC(sigpanic))) +} + +const pushCallSupported = true + +func (c *sigctxt) pushCall(targetPC uintptr) { + // Make it look like the signaled instruction called target. + pc := uintptr(c.eip()) + sp := uintptr(c.esp()) + sp -= sys.PtrSize + *(*uintptr)(unsafe.Pointer(sp)) = pc + c.set_esp(uint32(sp)) + c.set_eip(uint32(targetPC)) } diff --git a/src/runtime/signal_amd64.go b/src/runtime/signal_amd64.go index 9e9bb9ca33..29b6a9e7e6 100644 --- a/src/runtime/signal_amd64.go +++ b/src/runtime/signal_amd64.go @@ -66,14 +66,22 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { sp := uintptr(c.rsp()) if shouldPushSigpanic(gp, pc, *(*uintptr)(unsafe.Pointer(sp))) { - // Make it look the like faulting PC called sigpanic. - if sys.RegSize > sys.PtrSize { - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = 0 - } - sp -= sys.PtrSize - *(*uintptr)(unsafe.Pointer(sp)) = pc - c.set_rsp(uint64(sp)) + c.pushCall(funcPC(sigpanic)) + } else { + // Not safe to push the call. Just clobber the frame. + c.set_rip(uint64(funcPC(sigpanic))) } - c.set_rip(uint64(funcPC(sigpanic))) +} + +// TODO: Remove pushCallSupported once all platforms support it. +const pushCallSupported = true + +func (c *sigctxt) pushCall(targetPC uintptr) { + // Make it look like the signaled instruction called target. + pc := uintptr(c.rip()) + sp := uintptr(c.rsp()) + sp -= sys.PtrSize + *(*uintptr)(unsafe.Pointer(sp)) = pc + c.set_rsp(uint64(sp)) + c.set_rip(uint64(targetPC)) } diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go index 97742206c7..1b3e53d01c 100644 --- a/src/runtime/signal_arm.go +++ b/src/runtime/signal_arm.go @@ -62,3 +62,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r10(uint32(uintptr(unsafe.Pointer(gp)))) c.set_pc(uint32(funcPC(sigpanic))) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go index e1fe62d99d..2341d779da 100644 --- a/src/runtime/signal_arm64.go +++ b/src/runtime/signal_arm64.go @@ -78,3 +78,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r28(uint64(uintptr(unsafe.Pointer(gp)))) c.set_pc(uint64(funcPC(sigpanic))) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go index 6892f63b9f..390ff5db48 100644 --- a/src/runtime/signal_linux_s390x.go +++ b/src/runtime/signal_linux_s390x.go @@ -109,3 +109,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r13(uint64(uintptr(unsafe.Pointer(gp)))) c.set_pc(uint64(funcPC(sigpanic))) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go index 1b9684295e..3f1992c711 100644 --- a/src/runtime/signal_mips64x.go +++ b/src/runtime/signal_mips64x.go @@ -84,3 +84,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) c.set_pc(sigpanicPC) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go index e223c28402..6b5ed2872d 100644 --- a/src/runtime/signal_mipsx.go +++ b/src/runtime/signal_mipsx.go @@ -79,3 +79,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r30(uint32(uintptr(unsafe.Pointer(gp)))) c.set_pc(uint32(funcPC(sigpanic))) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go index cac1a23c9f..7befad40d2 100644 --- a/src/runtime/signal_ppc64x.go +++ b/src/runtime/signal_ppc64x.go @@ -85,3 +85,9 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) { c.set_r12(uint64(funcPC(sigpanic))) c.set_pc(uint64(funcPC(sigpanic))) } + +const pushCallSupported = false + +func (c *sigctxt) pushCall(targetPC uintptr) { + throw("not implemented") +} -- 2.50.0