aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/export_debug_amd64_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/export_debug_amd64_test.go')
-rw-r--r--src/runtime/export_debug_amd64_test.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/runtime/export_debug_amd64_test.go b/src/runtime/export_debug_amd64_test.go
new file mode 100644
index 0000000000..f9908cd494
--- /dev/null
+++ b/src/runtime/export_debug_amd64_test.go
@@ -0,0 +1,132 @@
+// Copyright 2022 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.
+
+//go:build amd64 && linux
+
+package runtime
+
+import (
+ "internal/abi"
+ "internal/goarch"
+ "unsafe"
+)
+
+type sigContext struct {
+ savedRegs sigcontext
+ // sigcontext.fpstate is a pointer, so we need to save
+ // the its value with a fpstate1 structure.
+ savedFP fpstate1
+}
+
+func sigctxtSetContextRegister(ctxt *sigctxt, x uint64) {
+ ctxt.regs().rdx = x
+}
+
+func sigctxtAtTrapInstruction(ctxt *sigctxt) bool {
+ return *(*byte)(unsafe.Pointer(uintptr(ctxt.rip() - 1))) == 0xcc // INT 3
+}
+
+func sigctxtStatus(ctxt *sigctxt) uint64 {
+ return ctxt.r12()
+}
+
+func (h *debugCallHandler) saveSigContext(ctxt *sigctxt) {
+ // Push current PC on the stack.
+ rsp := ctxt.rsp() - goarch.PtrSize
+ *(*uint64)(unsafe.Pointer(uintptr(rsp))) = ctxt.rip()
+ ctxt.set_rsp(rsp)
+ // Write the argument frame size.
+ *(*uintptr)(unsafe.Pointer(uintptr(rsp - 16))) = h.argSize
+ // Save current registers.
+ h.sigCtxt.savedRegs = *ctxt.regs()
+ h.sigCtxt.savedFP = *h.sigCtxt.savedRegs.fpstate
+ h.sigCtxt.savedRegs.fpstate = nil
+}
+
+// case 0
+func (h *debugCallHandler) debugCallRun(ctxt *sigctxt) {
+ rsp := ctxt.rsp()
+ memmove(unsafe.Pointer(uintptr(rsp)), h.argp, h.argSize)
+ if h.regArgs != nil {
+ storeRegArgs(ctxt.regs(), h.regArgs)
+ }
+ // Push return PC.
+ rsp -= goarch.PtrSize
+ ctxt.set_rsp(rsp)
+ // The signal PC is the next PC of the trap instruction.
+ *(*uint64)(unsafe.Pointer(uintptr(rsp))) = ctxt.rip()
+ // Set PC to call and context register.
+ ctxt.set_rip(uint64(h.fv.fn))
+ sigctxtSetContextRegister(ctxt, uint64(uintptr(unsafe.Pointer(h.fv))))
+}
+
+// case 1
+func (h *debugCallHandler) debugCallReturn(ctxt *sigctxt) {
+ rsp := ctxt.rsp()
+ memmove(h.argp, unsafe.Pointer(uintptr(rsp)), h.argSize)
+ if h.regArgs != nil {
+ loadRegArgs(h.regArgs, ctxt.regs())
+ }
+}
+
+// case 2
+func (h *debugCallHandler) debugCallPanicOut(ctxt *sigctxt) {
+ rsp := ctxt.rsp()
+ memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(rsp)), 2*goarch.PtrSize)
+}
+
+// case 8
+func (h *debugCallHandler) debugCallUnsafe(ctxt *sigctxt) {
+ rsp := ctxt.rsp()
+ reason := *(*string)(unsafe.Pointer(uintptr(rsp)))
+ h.err = plainError(reason)
+}
+
+// case 16
+func (h *debugCallHandler) restoreSigContext(ctxt *sigctxt) {
+ // Restore all registers except RIP and RSP.
+ rip, rsp := ctxt.rip(), ctxt.rsp()
+ fp := ctxt.regs().fpstate
+ *ctxt.regs() = h.sigCtxt.savedRegs
+ ctxt.regs().fpstate = fp
+ *fp = h.sigCtxt.savedFP
+ ctxt.set_rip(rip)
+ ctxt.set_rsp(rsp)
+}
+
+// storeRegArgs sets up argument registers in the signal
+// context state from an abi.RegArgs.
+//
+// Both src and dst must be non-nil.
+func storeRegArgs(dst *sigcontext, src *abi.RegArgs) {
+ dst.rax = uint64(src.Ints[0])
+ dst.rbx = uint64(src.Ints[1])
+ dst.rcx = uint64(src.Ints[2])
+ dst.rdi = uint64(src.Ints[3])
+ dst.rsi = uint64(src.Ints[4])
+ dst.r8 = uint64(src.Ints[5])
+ dst.r9 = uint64(src.Ints[6])
+ dst.r10 = uint64(src.Ints[7])
+ dst.r11 = uint64(src.Ints[8])
+ for i := range src.Floats {
+ dst.fpstate._xmm[i].element[0] = uint32(src.Floats[i] >> 0)
+ dst.fpstate._xmm[i].element[1] = uint32(src.Floats[i] >> 32)
+ }
+}
+
+func loadRegArgs(dst *abi.RegArgs, src *sigcontext) {
+ dst.Ints[0] = uintptr(src.rax)
+ dst.Ints[1] = uintptr(src.rbx)
+ dst.Ints[2] = uintptr(src.rcx)
+ dst.Ints[3] = uintptr(src.rdi)
+ dst.Ints[4] = uintptr(src.rsi)
+ dst.Ints[5] = uintptr(src.r8)
+ dst.Ints[6] = uintptr(src.r9)
+ dst.Ints[7] = uintptr(src.r10)
+ dst.Ints[8] = uintptr(src.r11)
+ for i := range dst.Floats {
+ dst.Floats[i] = uint64(src.fpstate._xmm[i].element[0]) << 0
+ dst.Floats[i] |= uint64(src.fpstate._xmm[i].element[1]) << 32
+ }
+}