aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/stack.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2018-04-26 21:43:19 -0400
committerAustin Clements <austin@google.com>2018-05-22 15:55:05 +0000
commitc5ed10f3bed104448b8c8f924e63a6d818c1ecb2 (patch)
treecb5dd9c31a9c7cae245db23dea8bf396e8f1f1ab /src/runtime/stack.go
parent9f95c9db23d9e137bc30c206b67b58cc325a8c7e (diff)
downloadgo-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.go36
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")