aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/export_debug_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/export_debug_test.go')
-rw-r--r--src/runtime/export_debug_test.go38
1 files changed, 24 insertions, 14 deletions
diff --git a/src/runtime/export_debug_test.go b/src/runtime/export_debug_test.go
index 18ccecd5cd..fe4c9045c1 100644
--- a/src/runtime/export_debug_test.go
+++ b/src/runtime/export_debug_test.go
@@ -8,19 +8,22 @@
package runtime
import (
+ "internal/abi"
"runtime/internal/sys"
"unsafe"
)
-// InjectDebugCall injects a debugger call to fn into g. args must be
-// a pointer to a valid call frame (including arguments and return
-// space) for fn, or nil. tkill must be a function that will send
-// SIGTRAP to thread ID tid. gp must be locked to its OS thread and
+// InjectDebugCall injects a debugger call to fn into g. regArgs must
+// contain any arguments to fn that are passed in registers, according
+// to the internal Go ABI. It may be nil if no arguments are passed in
+// registers to fn. args must be a pointer to a valid call frame (including
+// arguments and return space) for fn, or nil. tkill must be a function that
+// will send SIGTRAP to thread ID tid. gp must be locked to its OS thread and
// running.
//
// On success, InjectDebugCall returns the panic value of fn or nil.
// If fn did not panic, its results will be available in args.
-func InjectDebugCall(gp *g, fn, args interface{}, tkill func(tid int) error, returnOnUnsafePoint bool) (interface{}, error) {
+func InjectDebugCall(gp *g, fn interface{}, regArgs *abi.RegArgs, stackArgs interface{}, tkill func(tid int) error, returnOnUnsafePoint bool) (interface{}, error) {
if gp.lockedm == 0 {
return nil, plainError("goroutine not locked to thread")
}
@@ -36,7 +39,7 @@ func InjectDebugCall(gp *g, fn, args interface{}, tkill func(tid int) error, ret
}
fv := (*funcval)(f.data)
- a := efaceOf(&args)
+ a := efaceOf(&stackArgs)
if a._type != nil && a._type.kind&kindMask != kindPtr {
return nil, plainError("args must be a pointer or nil")
}
@@ -51,7 +54,7 @@ func InjectDebugCall(gp *g, fn, args interface{}, tkill func(tid int) error, ret
// gp may not be running right now, but we can still get the M
// it will run on since it's locked.
h.mp = gp.lockedm.ptr()
- h.fv, h.argp, h.argSize = fv, argp, argSize
+ h.fv, h.regArgs, h.argp, h.argSize = fv, regArgs, argp, argSize
h.handleF = h.handle // Avoid allocating closure during signal
defer func() { testSigtrap = nil }()
@@ -91,6 +94,7 @@ type debugCallHandler struct {
gp *g
mp *m
fv *funcval
+ regArgs *abi.RegArgs
argp unsafe.Pointer
argSize uintptr
panic interface{}
@@ -120,8 +124,8 @@ func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
h.savedRegs = *ctxt.regs()
h.savedFP = *h.savedRegs.fpstate
h.savedRegs.fpstate = nil
- // Set PC to debugCallV1.
- ctxt.set_rip(uint64(funcPC(debugCallV1)))
+ // Set PC to debugCallV2.
+ ctxt.set_rip(uint64(funcPC(debugCallV2)))
// Call injected. Switch to the debugCall protocol.
testSigtrap = h.handleF
case _Grunnable:
@@ -153,22 +157,28 @@ func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
return false
}
- switch status := ctxt.rax(); status {
+ switch status := ctxt.r12(); status {
case 0:
- // Frame is ready. Copy the arguments to the frame.
+ // 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 -= sys.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().rcx = uint64(uintptr(unsafe.Pointer(h.fv)))
+ ctxt.regs().rdx = uint64(uintptr(unsafe.Pointer(h.fv)))
case 1:
- // Function returned. Copy frame back out.
+ // 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())
+ }
case 2:
// Function panicked. Copy panic out.
sp := ctxt.rsp()
@@ -191,7 +201,7 @@ func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
// Done
notewakeup(&h.done)
default:
- h.err = plainError("unexpected debugCallV1 status")
+ h.err = plainError("unexpected debugCallV2 status")
notewakeup(&h.done)
}
// Resume execution.