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 {