diff options
| author | Austin Clements <austin@google.com> | 2018-04-26 21:43:19 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2018-05-22 15:55:05 +0000 |
| commit | c5ed10f3bed104448b8c8f924e63a6d818c1ecb2 (patch) | |
| tree | cb5dd9c31a9c7cae245db23dea8bf396e8f1f1ab /src/runtime/stack.go | |
| parent | 9f95c9db23d9e137bc30c206b67b58cc325a8c7e (diff) | |
| download | go-c5ed10f3bed104448b8c8f924e63a6d818c1ecb2.tar.xz | |
runtime: support for debugger function calls
This adds a mechanism for debuggers to safely inject calls to Go
functions on amd64. Debuggers must participate in a protocol with the
runtime, and need to know how to lay out a call frame, but the runtime
support takes care of the details of handling live pointers in
registers, stack growth, and detecting the trickier conditions when it
is unsafe to inject a user function call.
Fixes #21678.
Updates derekparker/delve#119.
Change-Id: I56d8ca67700f1f77e19d89e7fc92ab337b228834
Reviewed-on: https://go-review.googlesource.com/109699
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/stack.go')
| -rw-r--r-- | src/runtime/stack.go | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/src/runtime/stack.go b/src/runtime/stack.go index cbe49355a9..e40fa9cc1b 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1169,21 +1169,43 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args minsize = sys.MinFrameSize } if size > minsize { - stackmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) - if stackmap == nil || stackmap.n <= 0 { + var stkmap *stackmap + stackid := pcdata + if f.funcID != funcID_debugCallV1 { + stkmap = (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) + } else { + // debugCallV1's stack map is the register map + // at its call site. + callerPC := frame.lr + caller := findfunc(callerPC) + if !caller.valid() { + println("runtime: debugCallV1 called by unknown caller", hex(callerPC)) + throw("bad debugCallV1") + } + stackid = int32(-1) + if callerPC != caller.entry { + callerPC-- + stackid = pcdatavalue(caller, _PCDATA_RegMapIndex, callerPC, cache) + } + if stackid == -1 { + stackid = 0 // in prologue + } + stkmap = (*stackmap)(funcdata(caller, _FUNCDATA_RegPointerMaps)) + } + if stkmap == nil || stkmap.n <= 0 { print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n") throw("missing stackmap") } // If nbit == 0, there's no work to do. - if stackmap.nbit > 0 { - if pcdata < 0 || pcdata >= stackmap.n { + if stkmap.nbit > 0 { + if stackid < 0 || stackid >= stkmap.n { // don't know where we are - print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", hex(targetpc), ")\n") + print("runtime: pcdata is ", stackid, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", hex(targetpc), ")\n") throw("bad symbol table") } - locals = stackmapdata(stackmap, pcdata) + locals = stackmapdata(stkmap, stackid) if stackDebug >= 3 && debug { - print(" locals ", pcdata, "/", stackmap.n, " ", locals.n, " words ", locals.bytedata, "\n") + print(" locals ", stackid, "/", stkmap.n, " ", locals.n, " words ", locals.bytedata, "\n") } } else if stackDebug >= 3 && debug { print(" no locals to adjust\n") |
