From a2b839990e21690e9e60a74c582c4acece6196d8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 28 Jul 2021 11:18:20 -0400 Subject: [PATCH] Fix crashes on Go dev.typeparams (soon to be Go main branch) (#2627) * proc: Go 1.18 removes the _defer.siz field As of Go 1.17, the _defer.siz field is always 0 because _defer no longer stores defer call arguments at all. golang.org/cl/326062 removes it entirely for Go 1.18. Simply treat it as 0 if the field is missing from the _defer type. * proc: Go 1.18 changes _defer.fn from *funcval to func() golang.org/cl/325918 changed the type of the _defer.fn field from *funcval to func() for Go 1.18. This CL was later reverted because it caused failures in Delve, but we would like to un-revert it. Handle this change by inspecting the type of this field before decoding it. --- pkg/proc/stack.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go index 8460a26c..9448dd2f 100644 --- a/pkg/proc/stack.go +++ b/pkg/proc/stack.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "go/constant" + "reflect" "github.com/go-delve/delve/pkg/dwarf/frame" "github.com/go-delve/delve/pkg/dwarf/op" @@ -519,11 +520,11 @@ func (it *stackIterator) loadG0SchedSP() { // Defer represents one deferred call type Defer struct { - DwrapPC uint64 // Value of field _defer.fn.fn, the deferred function or a wrapper to it in Go 1.17 or later + DwrapPC uint64 // PC of the deferred function or, in Go 1.17+ a wrapper to it DeferPC uint64 // PC address of instruction that added this defer SP uint64 // Value of SP register when this function was deferred (this field gets adjusted when the stack is moved to match the new stack space) link *Defer // Next deferred function - argSz int64 + argSz int64 // Always 0 in Go >=1.17 variable *Variable Unreadable error @@ -580,8 +581,12 @@ func (d *Defer) load() { return } - fnvar := d.variable.fieldVariable("fn").maybeDereference() - if fnvar.Addr != 0 { + fnvar := d.variable.fieldVariable("fn") + if fnvar.Kind == reflect.Func { + // In Go 1.18, fn is a func(). + d.DwrapPC = fnvar.Base + } else if val := fnvar.maybeDereference(); val.Addr != 0 { + // In Go <1.18, fn is a *funcval. fnvar = fnvar.loadFieldNamed("fn") if fnvar.Unreadable == nil { d.DwrapPC, _ = constant.Uint64Val(fnvar.Value) @@ -590,7 +595,14 @@ func (d *Defer) load() { d.DeferPC, _ = constant.Uint64Val(d.variable.fieldVariable("pc").Value) d.SP, _ = constant.Uint64Val(d.variable.fieldVariable("sp").Value) - d.argSz, _ = constant.Int64Val(d.variable.fieldVariable("siz").Value) + sizVar := d.variable.fieldVariable("siz") + if sizVar != nil { + // In Go <1.18, siz stores the number of bytes of + // defer arguments following the defer record. In Go + // 1.18, the defer record doesn't store arguments, so + // we leave this 0. + d.argSz, _ = constant.Int64Val(sizVar.Value) + } linkvar := d.variable.fieldVariable("link").maybeDereference() if linkvar.Addr != 0 {