2015-09-10 09:21:57 -06:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2021-02-19 16:35:10 -07:00
|
|
|
//go:build (linux || openbsd) && (mips64 || mips64le)
|
2015-09-10 09:21:57 -06:00
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
2015-11-12 13:43:18 -07:00
|
|
|
import (
|
2021-05-21 11:37:19 -06:00
|
|
|
"internal/abi"
|
2021-06-16 17:05:44 -06:00
|
|
|
"internal/goarch"
|
2015-11-12 13:43:18 -07:00
|
|
|
"unsafe"
|
|
|
|
)
|
2015-09-10 09:21:57 -06:00
|
|
|
|
|
|
|
func dumpregs(c *sigctxt) {
|
|
|
|
print("r0 ", hex(c.r0()), "\t")
|
|
|
|
print("r1 ", hex(c.r1()), "\n")
|
|
|
|
print("r2 ", hex(c.r2()), "\t")
|
|
|
|
print("r3 ", hex(c.r3()), "\n")
|
|
|
|
print("r4 ", hex(c.r4()), "\t")
|
|
|
|
print("r5 ", hex(c.r5()), "\n")
|
|
|
|
print("r6 ", hex(c.r6()), "\t")
|
|
|
|
print("r7 ", hex(c.r7()), "\n")
|
|
|
|
print("r8 ", hex(c.r8()), "\t")
|
|
|
|
print("r9 ", hex(c.r9()), "\n")
|
|
|
|
print("r10 ", hex(c.r10()), "\t")
|
|
|
|
print("r11 ", hex(c.r11()), "\n")
|
|
|
|
print("r12 ", hex(c.r12()), "\t")
|
|
|
|
print("r13 ", hex(c.r13()), "\n")
|
|
|
|
print("r14 ", hex(c.r14()), "\t")
|
|
|
|
print("r15 ", hex(c.r15()), "\n")
|
|
|
|
print("r16 ", hex(c.r16()), "\t")
|
|
|
|
print("r17 ", hex(c.r17()), "\n")
|
|
|
|
print("r18 ", hex(c.r18()), "\t")
|
|
|
|
print("r19 ", hex(c.r19()), "\n")
|
|
|
|
print("r20 ", hex(c.r20()), "\t")
|
|
|
|
print("r21 ", hex(c.r21()), "\n")
|
|
|
|
print("r22 ", hex(c.r22()), "\t")
|
|
|
|
print("r23 ", hex(c.r23()), "\n")
|
|
|
|
print("r24 ", hex(c.r24()), "\t")
|
|
|
|
print("r25 ", hex(c.r25()), "\n")
|
|
|
|
print("r26 ", hex(c.r26()), "\t")
|
|
|
|
print("r27 ", hex(c.r27()), "\n")
|
|
|
|
print("r28 ", hex(c.r28()), "\t")
|
|
|
|
print("r29 ", hex(c.r29()), "\n")
|
|
|
|
print("r30 ", hex(c.r30()), "\t")
|
|
|
|
print("r31 ", hex(c.r31()), "\n")
|
|
|
|
print("pc ", hex(c.pc()), "\t")
|
|
|
|
print("link ", hex(c.link()), "\n")
|
|
|
|
print("lo ", hex(c.lo()), "\t")
|
|
|
|
print("hi ", hex(c.hi()), "\n")
|
|
|
|
}
|
|
|
|
|
2016-10-04 08:11:55 -06:00
|
|
|
//go:nosplit
|
|
|
|
//go:nowritebarrierrec
|
2016-09-23 23:05:51 -06:00
|
|
|
func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
|
2016-10-04 08:11:55 -06:00
|
|
|
|
2016-09-23 23:05:51 -06:00
|
|
|
func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
|
|
|
|
func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) }
|
|
|
|
func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
|
|
|
|
|
|
|
|
// preparePanic sets up the stack to look like a call to sigpanic.
|
|
|
|
func (c *sigctxt) preparePanic(sig uint32, gp *g) {
|
|
|
|
// We arrange link, and pc to pretend the panicking
|
|
|
|
// function calls sigpanic directly.
|
|
|
|
// Always save LINK to stack so that panics in leaf
|
|
|
|
// functions are correctly handled. This smashes
|
|
|
|
// the stack frame but we're not going back there
|
|
|
|
// anyway.
|
2021-06-16 17:05:44 -06:00
|
|
|
sp := c.sp() - goarch.PtrSize
|
2016-09-23 23:05:51 -06:00
|
|
|
c.set_sp(sp)
|
|
|
|
*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
|
|
|
|
|
|
|
|
pc := gp.sigpc
|
|
|
|
|
2018-01-31 15:34:22 -07:00
|
|
|
if shouldPushSigpanic(gp, pc, uintptr(c.link())) {
|
|
|
|
// Make it look the like faulting PC called sigpanic.
|
2016-09-23 23:05:51 -06:00
|
|
|
c.set_link(uint64(pc))
|
2015-09-10 09:21:57 -06:00
|
|
|
}
|
|
|
|
|
2016-09-23 23:05:51 -06:00
|
|
|
// In case we are panicking from external C code
|
2021-05-21 11:37:19 -06:00
|
|
|
sigpanicPC := uint64(abi.FuncPCABIInternal(sigpanic))
|
2018-01-31 12:34:36 -07:00
|
|
|
c.set_r28(sigpanicPC >> 32 << 32) // RSB register
|
2016-09-23 23:05:51 -06:00
|
|
|
c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
|
2018-01-31 12:34:36 -07:00
|
|
|
c.set_pc(sigpanicPC)
|
2015-09-10 09:21:57 -06:00
|
|
|
}
|
2019-10-14 17:28:58 -06:00
|
|
|
|
cmd/internal/obj, runtime: preempt & restart some instruction sequences
On some architectures, for async preemption the injected call
needs to clobber a register (usually REGTMP) in order to return
to the preempted function. As a consequence, the PC ranges where
REGTMP is live are not preemptible.
The uses of REGTMP are usually generated by the assembler, where
it needs to load or materialize a large constant or offset that
doesn't fit into the instruction. In those cases, REGTMP is not
live at the start of the instruction sequence. Instead of giving
up preemption in those cases, we could preempt it and restart the
sequence when resuming the execution. Basically, this is like
reissuing an interrupted instruction, except that here the
"instruction" is a Prog that consists of multiple machine
instructions. For this to work, we need to generate PC data to
mark the start of the Prog.
Currently this is only done for ARM64.
TODO: the split-stack function prologue is currently not async
preemptible. We could use this mechanism, preempt it and restart
at the function entry.
Change-Id: I37cb282f8e606e7ab6f67b3edfdc6063097b4bd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/208126
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2019-11-20 15:10:34 -07:00
|
|
|
func (c *sigctxt) pushCall(targetPC, resumePC uintptr) {
|
2019-10-26 20:54:28 -06:00
|
|
|
// Push the LR to stack, as we'll clobber it in order to
|
|
|
|
// push the call. The function being pushed is responsible
|
|
|
|
// for restoring the LR and setting the SP back.
|
|
|
|
// This extra slot is known to gentraceback.
|
|
|
|
sp := c.sp() - 8
|
|
|
|
c.set_sp(sp)
|
|
|
|
*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
|
|
|
|
// Set up PC and LR to pretend the function being signaled
|
cmd/internal/obj, runtime: preempt & restart some instruction sequences
On some architectures, for async preemption the injected call
needs to clobber a register (usually REGTMP) in order to return
to the preempted function. As a consequence, the PC ranges where
REGTMP is live are not preemptible.
The uses of REGTMP are usually generated by the assembler, where
it needs to load or materialize a large constant or offset that
doesn't fit into the instruction. In those cases, REGTMP is not
live at the start of the instruction sequence. Instead of giving
up preemption in those cases, we could preempt it and restart the
sequence when resuming the execution. Basically, this is like
reissuing an interrupted instruction, except that here the
"instruction" is a Prog that consists of multiple machine
instructions. For this to work, we need to generate PC data to
mark the start of the Prog.
Currently this is only done for ARM64.
TODO: the split-stack function prologue is currently not async
preemptible. We could use this mechanism, preempt it and restart
at the function entry.
Change-Id: I37cb282f8e606e7ab6f67b3edfdc6063097b4bd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/208126
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2019-11-20 15:10:34 -07:00
|
|
|
// calls targetPC at resumePC.
|
|
|
|
c.set_link(uint64(resumePC))
|
2019-10-26 20:54:28 -06:00
|
|
|
c.set_pc(uint64(targetPC))
|
2019-10-14 17:28:58 -06:00
|
|
|
}
|