diff options
Diffstat (limited to 'src/runtime/export_debug_test.go')
| -rw-r--r-- | src/runtime/export_debug_test.go | 38 |
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. |
