1
0
mirror of https://github.com/golang/go synced 2024-11-16 21:44:52 -07:00
go/src/runtime/export_debug_amd64_test.go
eric fang 9717e8f80f runtime: support for debugger function calls on linux/arm64
This CL adds support for debugger function calls on linux arm64
platform. The protocol is basically the same as in CL 109699, except for
the following differences:
1, The abi difference which affect parameter passing and frame layout.
2, Stores communication information in R20.
3, The closure register is R26.
4, Use BRK 0 instruction to generate a breakpoint. The saved PC in
sigcontext is the PC where the signal occurred, not the next PC.

In addition, this CL refactors the existing code (which is dedicated to
amd64) for easier multi-arch scaling.

Fixes #50614

Change-Id: I06b14e345cc89aab175f4a5f2287b765da85a86b
Reviewed-on: https://go-review.googlesource.com/c/go/+/395754
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Eric Fang <eric.fang@arm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-04-23 05:38:56 +00:00

133 lines
3.6 KiB
Go

// 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
}
}