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.
This commit is contained in:
Austin Clements 2021-07-28 11:18:20 -04:00 committed by GitHub
parent cb73ef8f83
commit a2b839990e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"go/constant" "go/constant"
"reflect"
"github.com/go-delve/delve/pkg/dwarf/frame" "github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/op" "github.com/go-delve/delve/pkg/dwarf/op"
@ -519,11 +520,11 @@ func (it *stackIterator) loadG0SchedSP() {
// Defer represents one deferred call // Defer represents one deferred call
type Defer struct { 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 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) 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 link *Defer // Next deferred function
argSz int64 argSz int64 // Always 0 in Go >=1.17
variable *Variable variable *Variable
Unreadable error Unreadable error
@ -580,8 +581,12 @@ func (d *Defer) load() {
return return
} }
fnvar := d.variable.fieldVariable("fn").maybeDereference() fnvar := d.variable.fieldVariable("fn")
if fnvar.Addr != 0 { 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") fnvar = fnvar.loadFieldNamed("fn")
if fnvar.Unreadable == nil { if fnvar.Unreadable == nil {
d.DwrapPC, _ = constant.Uint64Val(fnvar.Value) d.DwrapPC, _ = constant.Uint64Val(fnvar.Value)
@ -590,7 +595,14 @@ func (d *Defer) load() {
d.DeferPC, _ = constant.Uint64Val(d.variable.fieldVariable("pc").Value) d.DeferPC, _ = constant.Uint64Val(d.variable.fieldVariable("pc").Value)
d.SP, _ = constant.Uint64Val(d.variable.fieldVariable("sp").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() linkvar := d.variable.fieldVariable("link").maybeDereference()
if linkvar.Addr != 0 { if linkvar.Addr != 0 {