diff options
| author | eric fang <eric.fang@arm.com> | 2022-03-22 07:04:35 +0000 |
|---|---|---|
| committer | Eric Fang <eric.fang@arm.com> | 2022-04-23 05:38:56 +0000 |
| commit | 9717e8f80f973e747a6c6e4a938c7f2a091a9b50 (patch) | |
| tree | bc732bc7bd3edc3963aba165cc03d70d8a23e5cb /src/runtime/export_debug_test.go | |
| parent | 7c680974c66ca23f837cb4bee5587df8b05418c7 (diff) | |
| download | go-9717e8f80f973e747a6c6e4a938c7f2a091a9b50.tar.xz | |
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>
Diffstat (limited to 'src/runtime/export_debug_test.go')
| -rw-r--r-- | src/runtime/export_debug_test.go | 68 |
1 files changed, 17 insertions, 51 deletions
diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go index 19a9ec135f..09e9779696 100644 --- a/src/runtime/export_debug_test.go +++ b/src/runtime/export_debug_test.go @@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 && linux +//go:build (amd64 || arm64) && linux package runtime import ( "internal/abi" - "internal/goarch" "unsafe" ) @@ -100,10 +99,9 @@ type debugCallHandler struct { handleF func(info *siginfo, ctxt *sigctxt, gp2 *g) bool - err plainError - done note - savedRegs sigcontext - savedFP fpstate1 + err plainError + done note + sigCtxt sigContext } func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool { @@ -117,18 +115,10 @@ func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool { println("trap on wrong M", getg().m, h.mp) return false } - // 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.savedRegs = *ctxt.regs() - h.savedFP = *h.savedRegs.fpstate - h.savedRegs.fpstate = nil + // Save the signal context + h.saveSigContext(ctxt) // Set PC to debugCallV2. - ctxt.set_rip(uint64(abi.FuncPCABIInternal(debugCallV2))) + ctxt.setsigpc(uint64(abi.FuncPCABIInternal(debugCallV2))) // Call injected. Switch to the debugCall protocol. testSigtrap = h.handleF case _Grunnable: @@ -154,57 +144,33 @@ func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool { println("trap on wrong M", getg().m, h.mp) return false } - f := findfunc(uintptr(ctxt.rip())) + f := findfunc(ctxt.sigpc()) if !(hasPrefix(funcname(f), "runtime.debugCall") || hasPrefix(funcname(f), "debugCall")) { println("trap in unknown function", funcname(f)) return false } - if *(*byte)(unsafe.Pointer(uintptr(ctxt.rip() - 1))) != 0xcc { - println("trap at non-INT3 instruction pc =", hex(ctxt.rip())) + if !sigctxtAtTrapInstruction(ctxt) { + println("trap at non-INT3 instruction pc =", hex(ctxt.sigpc())) return false } - switch status := ctxt.r12(); status { + switch status := sigctxtStatus(ctxt); status { case 0: // Frame is ready. Copy the arguments to the frame and to registers. - sp := ctxt.rsp() - memmove(unsafe.Pointer(uintptr(sp)), h.argp, h.argSize) - if h.regArgs != nil { - storeRegArgs(ctxt.regs(), h.regArgs) - } - // Push return PC. - sp -= goarch.PtrSize - ctxt.set_rsp(sp) - *(*uint64)(unsafe.Pointer(uintptr(sp))) = ctxt.rip() - // Set PC to call and context register. - ctxt.set_rip(uint64(h.fv.fn)) - ctxt.regs().rdx = uint64(uintptr(unsafe.Pointer(h.fv))) + // Call the debug function. + h.debugCallRun(ctxt) case 1: // Function returned. Copy frame and result registers back out. - sp := ctxt.rsp() - memmove(h.argp, unsafe.Pointer(uintptr(sp)), h.argSize) - if h.regArgs != nil { - loadRegArgs(h.regArgs, ctxt.regs()) - } + h.debugCallReturn(ctxt) case 2: // Function panicked. Copy panic out. - sp := ctxt.rsp() - memmove(unsafe.Pointer(&h.panic), unsafe.Pointer(uintptr(sp)), 2*goarch.PtrSize) + h.debugCallPanicOut(ctxt) case 8: // Call isn't safe. Get the reason. - sp := ctxt.rsp() - reason := *(*string)(unsafe.Pointer(uintptr(sp))) - h.err = plainError(reason) + h.debugCallUnsafe(ctxt) // Don't wake h.done. We need to transition to status 16 first. case 16: - // Restore all registers except RIP and RSP. - rip, rsp := ctxt.rip(), ctxt.rsp() - fp := ctxt.regs().fpstate - *ctxt.regs() = h.savedRegs - ctxt.regs().fpstate = fp - *fp = h.savedFP - ctxt.set_rip(rip) - ctxt.set_rsp(rsp) + h.restoreSigContext(ctxt) // Done notewakeup(&h.done) default: |
