From 091ff506450c260d89c5f2a7c03bbcdf7eb47419 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 17 Jun 2025 16:04:52 -0700 Subject: [PATCH] proc: handle moving of direct interface flag in Go 1.26 (#4032) This flag in internal/abi.Type is moving from the Kind_ field to the TFlag field. See https://go-review.googlesource.com/c/go/+/681936 A few of the other Kind fields dlv doesn't use (and don't exist in Go anymore), so this code can be simplified somewhat. --- _scripts/rtype-out.txt | 6 ++---- pkg/proc/bininfo.go | 2 +- pkg/proc/types.go | 43 ++++++++++++++++++++++++++++-------------- pkg/proc/variables.go | 4 ++-- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/_scripts/rtype-out.txt b/_scripts/rtype-out.txt index a592eb39..bada8bbb 100644 --- a/_scripts/rtype-out.txt +++ b/_scripts/rtype-out.txt @@ -67,10 +67,8 @@ const internal/runtime/maps.ctrlEmpty = 128 const kindDirectIface|internal/abi.KindDirectIface = 32 -const kindGCProg|internal/abi.KindGCProg = 64 - -const kindMask|internal/abi.KindMask = 31 - const minTopHash = 4 or const minTopHash = 5 +const tflagDirectIface|internal/abi.TFlagDirectIface = 32 + diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index 722f61b0..4149651f 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -1026,7 +1026,7 @@ type Image struct { func (image *Image) registerRuntimeTypeToDIE(entry *dwarf.Entry, ardr *reader.Reader) { if off, ok := entry.Val(godwarf.AttrGoRuntimeType).(uint64); ok { if _, ok := image.runtimeTypeToDIE[off]; !ok { - image.runtimeTypeToDIE[off] = runtimeTypeDIE{entry.Offset, -1} + image.runtimeTypeToDIE[off] = runtimeTypeDIE{entry.Offset} } } } diff --git a/pkg/proc/types.go b/pkg/proc/types.go index 64fe879c..1e64a7f3 100644 --- a/pkg/proc/types.go +++ b/pkg/proc/types.go @@ -13,17 +13,16 @@ import ( // The kind field in runtime._type is a reflect.Kind value plus // some extra flags defined here. -// See equivalent declaration in $GOROOT/src/reflect/type.go +// See equivalent declaration in $GOROOT/src/internal/abi/type.go const ( + // Go 1.25 and earlier kindDirectIface = 1 << 5 // +rtype kindDirectIface|internal/abi.KindDirectIface - kindGCProg = 1 << 6 // +rtype kindGCProg|internal/abi.KindGCProg - kindNoPointers = 1 << 7 - kindMask = (1 << 5) - 1 // +rtype kindMask|internal/abi.KindMask + // Go 1.26 and later + tflagDirectIface = 1 << 5 // +rtype go1.26 tflagDirectIface|internal/abi.TFlagDirectIface ) type runtimeTypeDIE struct { offset dwarf.Offset - kind int64 } func pointerTo(typ godwarf.Type, arch *Arch) godwarf.Type { @@ -80,7 +79,7 @@ func (ctxt *loadDebugInfoMapsContext) lookupAbstractOrigin(bi *BinaryInfo, off d // debug_info // - After go1.11 the runtimeTypeToDIE map is used to look up the address of // the type and map it directly to a DIE. -func RuntimeTypeToDIE(_type *Variable, dataAddr uint64, mds []ModuleData) (typ godwarf.Type, kind int64, err error) { +func RuntimeTypeToDIE(_type *Variable, dataAddr uint64, mds []ModuleData) (typ godwarf.Type, directIface bool, err error) { bi := _type.bi _type = _type.maybeDereference() @@ -94,21 +93,37 @@ func RuntimeTypeToDIE(_type *Variable, dataAddr uint64, mds []ModuleData) (typ g if rtdie, ok := so.runtimeTypeToDIE[_type.Addr-md.types]; ok { typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache) if err != nil { - return nil, 0, fmt.Errorf("invalid interface type: %v", err) + return nil, false, fmt.Errorf("invalid interface type: %v", err) } - if rtdie.kind == -1 { - if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { - rtdie.kind, _ = constant.Int64Val(kindField.Value) - } else if kindField := _type.loadFieldNamed("Kind_"); kindField != nil && kindField.Value != nil { - rtdie.kind, _ = constant.Int64Val(kindField.Value) + // Figure out whether interfaces with this concrete type are direct or not. + // Go 1.26 and beyond have this flag in the TFlag field. + // Go 1.25 and earlier have this flag in the Kind field. + // If either flag is set, consider it direct. + var direct bool + if tflagField := _type.loadFieldNamed("TFlag"); tflagField != nil && tflagField.Value != nil { + tflag, _ := constant.Int64Val(tflagField.Value) + if tflag&tflagDirectIface != 0 { + direct = true } } - return typ, rtdie.kind, nil + if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { + kind, _ := constant.Int64Val(kindField.Value) + if kind&kindDirectIface != 0 { + direct = true + } + } else if kindField := _type.loadFieldNamed("Kind_"); kindField != nil && kindField.Value != nil { + kind, _ := constant.Int64Val(kindField.Value) + if kind&kindDirectIface != 0 { + direct = true + } + } + + return typ, direct, nil } } } - return nil, 0, errors.New("could not resolve interface type") + return nil, false, errors.New("could not resolve interface type") } // resolveParametricType returns the real type of t if t is a parametric diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go index 539bff3d..7007e49b 100644 --- a/pkg/proc/variables.go +++ b/pkg/proc/variables.go @@ -2135,14 +2135,14 @@ func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig return } - typ, kind, err := RuntimeTypeToDIE(_type, data.Addr, mds) + typ, directIface, err := RuntimeTypeToDIE(_type, data.Addr, mds) if err != nil { v.Unreadable = err return } deref := false - if kind&kindDirectIface == 0 { + if !directIface { realtyp := godwarf.ResolveTypedef(typ) if _, isptr := realtyp.(*godwarf.PtrType); !isptr { typ = pointerTo(typ, v.bi.Arch)