go/src/runtime/export_debug_ppc64le_test.go
Archana b0ae440bf0 runtime: support for debugger function calls on linux/ppc64le
This CL adds support for debugger function calls on linux ppc64le
platform. The protocol is basically the same as in CL 395754, except for
the following differences:
1, The abi differences which affect parameter passing and frame layout.
2, The closure register is R11.
3, Minimum framesize on pp64le is 32 bytes
4, Added functions to return parent context structure for general purpose
   registers in order to work with the way these structures are defined in
   ppc64le

Change-Id: I58e01fedad66a818ab322e2b2d8f5104cfa64f39
Reviewed-on: https://go-review.googlesource.com/c/go/+/512575
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Archana Ravindar <aravinda@redhat.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2023-09-08 15:08:04 +00:00

132 lines
3.5 KiB
Go

// Copyright 2023 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 ppc64le && linux
package runtime
import (
"internal/abi"
"internal/goarch"
"math"
"unsafe"
)
type sigContext struct {
savedRegs sigcontext
}
func sigctxtSetContextRegister(ctxt *sigctxt, x uint64) {
ctxt.regs().gpr[11] = x
}
func sigctxtAtTrapInstruction(ctxt *sigctxt) bool {
return *(*uint32)(unsafe.Pointer(ctxt.sigpc())) == 0x7fe00008 // Trap
}
func sigctxtStatus(ctxt *sigctxt) uint64 {
return ctxt.r20()
}
func (h *debugCallHandler) saveSigContext(ctxt *sigctxt) {
sp := ctxt.sp()
sp -= 4 * goarch.PtrSize
ctxt.set_sp(sp)
*(*uint64)(unsafe.Pointer(uintptr(sp))) = ctxt.link() // save the current lr
ctxt.set_link(ctxt.pc()) // set new lr to the current pc
// Write the argument frame size.
*(*uintptr)(unsafe.Pointer(uintptr(sp - 32))) = h.argSize
// Save current registers.
h.sigCtxt.savedRegs = *ctxt.cregs()
}
// case 0
func (h *debugCallHandler) debugCallRun(ctxt *sigctxt) {
sp := ctxt.sp()
memmove(unsafe.Pointer(uintptr(sp)+32), h.argp, h.argSize)
if h.regArgs != nil {
storeRegArgs(ctxt.cregs(), h.regArgs)
}
// Push return PC, which should be the signal PC+4, because
// the signal PC is the PC of the trap instruction itself.
ctxt.set_link(ctxt.pc() + 4)
// Set PC to call and context register.
ctxt.set_pc(uint64(h.fv.fn))
sigctxtSetContextRegister(ctxt, uint64(uintptr(unsafe.Pointer(h.fv))))
}
// case 1
func (h *debugCallHandler) debugCallReturn(ctxt *sigctxt) {
sp := ctxt.sp()
memmove(h.argp, unsafe.Pointer(uintptr(sp)+32), h.argSize)
if h.regArgs != nil {
loadRegArgs(h.regArgs, ctxt.cregs())
}
// Restore the old lr from *sp
olr := *(*uint64)(unsafe.Pointer(uintptr(sp)))
ctxt.set_link(olr)
pc := ctxt.pc()
ctxt.set_pc(pc + 4) // step to next instruction
}
// case 2
func (h *debugCallHandler) debugCallPanicOut(ctxt *sigctxt) {
sp := ctxt.sp()
memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(sp)+32), 2*goarch.PtrSize)
ctxt.set_pc(ctxt.pc() + 4)
}
// case 8
func (h *debugCallHandler) debugCallUnsafe(ctxt *sigctxt) {
sp := ctxt.sp()
reason := *(*string)(unsafe.Pointer(uintptr(sp) + 40))
h.err = plainError(reason)
ctxt.set_pc(ctxt.pc() + 4)
}
// case 16
func (h *debugCallHandler) restoreSigContext(ctxt *sigctxt) {
// Restore all registers except for pc and sp
pc, sp := ctxt.pc(), ctxt.sp()
*ctxt.cregs() = h.sigCtxt.savedRegs
ctxt.set_pc(pc + 4)
ctxt.set_sp(sp)
}
// 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) {
// Gprs R3..R10, R14..R17 are used to pass int arguments in registers on PPC64
for i := 0; i < 12; i++ {
if i > 7 {
dst.gp_regs[i+6] = uint64(src.Ints[i])
} else {
dst.gp_regs[i+3] = uint64(src.Ints[i])
}
}
// Fprs F1..F13 are used to pass float arguments in registers on PPC64
for i := 0; i < 12; i++ {
dst.fp_regs[i+1] = math.Float64frombits(src.Floats[i])
}
}
func loadRegArgs(dst *abi.RegArgs, src *sigcontext) {
// Gprs R3..R10, R14..R17 are used to pass int arguments in registers on PPC64
for i, _ := range [12]int{} {
if i > 7 {
dst.Ints[i] = uintptr(src.gp_regs[i+6])
} else {
dst.Ints[i] = uintptr(src.gp_regs[i+3])
}
}
// Fprs F1..F13 are used to pass float arguments in registers on PPC64
for i, _ := range [12]int{} {
dst.Floats[i] = math.Float64bits(src.fp_regs[i+1])
}
}