proc: fix runtime type handling for Go 1.21 (#3370)
Go 1.21 renamed runtime._type to internal/abi.Type and changed the name of its fields. Update Delve so that it uses the new names for loading interfaces and generic type parameters.
This commit is contained in:
parent
e95ae9c21b
commit
674bd63996
@ -15,7 +15,7 @@ type bmap struct {
|
||||
}
|
||||
|
||||
type eface struct {
|
||||
_type *_type
|
||||
_type *_type|*internal/abi.Type
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ type iface struct {
|
||||
}
|
||||
|
||||
type itab struct {
|
||||
_type *_type
|
||||
_type *_type|*internal/abi.Type
|
||||
}
|
||||
|
||||
type moduledata struct {
|
||||
|
@ -900,6 +900,13 @@ func (bi *BinaryInfo) typeToImage(typ godwarf.Type) *Image {
|
||||
return bi.Images[typ.Common().Index]
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) runtimeTypeTypename() string {
|
||||
if goversion.ProducerAfterOrEqual(bi.Producer(), 1, 21) {
|
||||
return "internal/abi.Type"
|
||||
}
|
||||
return "runtime._type"
|
||||
}
|
||||
|
||||
var errBinaryInfoClose = errors.New("multiple errors closing executable files")
|
||||
|
||||
// Close closes all internal readers.
|
||||
@ -2130,10 +2137,11 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineB
|
||||
if fn != nil && fn.cu.image == image {
|
||||
tree, err := image.getDwarfTree(fn.offset)
|
||||
if err == nil {
|
||||
tree.Children, err = regabiMallocgcWorkaround(bi)
|
||||
children, err := regabiMallocgcWorkaround(bi)
|
||||
if err != nil {
|
||||
bi.logger.Errorf("could not patch runtime.mallogc: %v", err)
|
||||
bi.logger.Errorf("could not patch runtime.mallocgc: %v", err)
|
||||
} else {
|
||||
tree.Children = children
|
||||
image.runtimeMallocgcTree = tree
|
||||
}
|
||||
}
|
||||
|
@ -1263,6 +1263,8 @@ func (e fakeEntry) AttrField(attr dwarf.Attr) *dwarf.Field {
|
||||
}
|
||||
|
||||
func regabiMallocgcWorkaround(bi *BinaryInfo) ([]*godwarf.Tree, error) {
|
||||
ptrToRuntimeType := "*" + bi.runtimeTypeTypename()
|
||||
|
||||
var err1 error
|
||||
|
||||
t := func(name string) godwarf.Type {
|
||||
@ -1298,7 +1300,7 @@ func regabiMallocgcWorkaround(bi *BinaryInfo) ([]*godwarf.Tree, error) {
|
||||
case "amd64":
|
||||
r := []*godwarf.Tree{
|
||||
m("size", t("uintptr"), regnum.AMD64_Rax, false),
|
||||
m("typ", t("*runtime._type"), regnum.AMD64_Rbx, false),
|
||||
m("typ", t(ptrToRuntimeType), regnum.AMD64_Rbx, false),
|
||||
m("needzero", t("bool"), regnum.AMD64_Rcx, false),
|
||||
m("~r1", t("unsafe.Pointer"), regnum.AMD64_Rax, true),
|
||||
}
|
||||
@ -1306,7 +1308,7 @@ func regabiMallocgcWorkaround(bi *BinaryInfo) ([]*godwarf.Tree, error) {
|
||||
case "arm64":
|
||||
r := []*godwarf.Tree{
|
||||
m("size", t("uintptr"), regnum.ARM64_X0, false),
|
||||
m("typ", t("*runtime._type"), regnum.ARM64_X0+1, false),
|
||||
m("typ", t(ptrToRuntimeType), regnum.ARM64_X0+1, false),
|
||||
m("needzero", t("bool"), regnum.ARM64_X0+2, false),
|
||||
m("~r1", t("unsafe.Pointer"), regnum.ARM64_X0, true),
|
||||
}
|
||||
|
@ -4647,7 +4647,10 @@ func TestCgoStacktrace2(t *testing.T) {
|
||||
// If a panic happens during cgo execution the stacktrace should show the C
|
||||
// function that caused the problem.
|
||||
withTestProcess("cgosigsegvstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
||||
grp.Continue()
|
||||
err := grp.Continue()
|
||||
if _, exited := err.(proc.ErrProcessExited); exited {
|
||||
t.Fatal("process exited")
|
||||
}
|
||||
frames, err := proc.ThreadStacktrace(p.CurrentThread(), 100)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
logStacktrace(t, p, frames)
|
||||
@ -5099,6 +5102,7 @@ func TestStepOutPreservesGoroutine(t *testing.T) {
|
||||
candg := []*proc.G{}
|
||||
bestg := []*proc.G{}
|
||||
for _, g := range gs {
|
||||
t.Logf("stacktracing goroutine %d (%v)\n", g.ID, g.CurrentLoc)
|
||||
frames, err := g.Stacktrace(20, 0)
|
||||
assertNoError(err, t, "Stacktrace")
|
||||
for _, frame := range frames {
|
||||
|
@ -122,6 +122,8 @@ func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind
|
||||
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)
|
||||
}
|
||||
}
|
||||
return typ, rtdie.kind, nil
|
||||
@ -146,7 +148,7 @@ func resolveParametricType(bi *BinaryInfo, mem MemoryReadWriter, t godwarf.Type,
|
||||
if err != nil {
|
||||
return ptyp.TypedefType.Type, err
|
||||
}
|
||||
runtimeType, err := bi.findType("runtime._type")
|
||||
runtimeType, err := bi.findType(bi.runtimeTypeTypename())
|
||||
if err != nil {
|
||||
return ptyp.TypedefType.Type, err
|
||||
}
|
||||
@ -189,13 +191,16 @@ func dwarfToRuntimeType(bi *BinaryInfo, mem MemoryReadWriter, typ godwarf.Type)
|
||||
|
||||
typeAddr = uint64(md.types) + off
|
||||
|
||||
rtyp, err := bi.findType("runtime._type")
|
||||
rtyp, err := bi.findType(bi.runtimeTypeTypename())
|
||||
if err != nil {
|
||||
return 0, 0, false, err
|
||||
}
|
||||
_type := newVariable("", typeAddr, rtyp, bi, mem)
|
||||
kindv := _type.loadFieldNamed("kind")
|
||||
if kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
|
||||
if kindv == nil || kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
|
||||
kindv = _type.loadFieldNamed("Kind_")
|
||||
}
|
||||
if kindv == nil || kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
|
||||
return 0, 0, false, fmt.Errorf("unreadable interface type: %v", kindv.Unreadable)
|
||||
}
|
||||
typeKind, _ = constant.Uint64Val(kindv.Value)
|
||||
|
@ -671,7 +671,7 @@ func newVariable(name string, addr uint64, dwarfType godwarf.Type, bi *BinaryInf
|
||||
v.stride = 1
|
||||
v.fieldType = &godwarf.UintType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: 1, Name: "byte", ReflectKind: reflect.Uint8}, BitSize: 8, BitOffset: 0}}
|
||||
if v.Addr != 0 {
|
||||
v.Base, v.Len, v.Unreadable = readStringInfo(v.mem, v.bi.Arch, v.Addr)
|
||||
v.Base, v.Len, v.Unreadable = readStringInfo(v.mem, v.bi.Arch, v.Addr, t)
|
||||
}
|
||||
case *godwarf.SliceType:
|
||||
v.Kind = reflect.Slice
|
||||
@ -1455,30 +1455,38 @@ func convertToEface(srcv, dstv *Variable) error {
|
||||
return dstv.writeEmptyInterface(typeAddr, srcv)
|
||||
}
|
||||
|
||||
func readStringInfo(mem MemoryReadWriter, arch *Arch, addr uint64) (uint64, int64, error) {
|
||||
func readStringInfo(mem MemoryReadWriter, arch *Arch, addr uint64, typ *godwarf.StringType) (uint64, int64, error) {
|
||||
// string data structure is always two ptrs in size. Addr, followed by len
|
||||
// http://research.swtch.com/godata
|
||||
|
||||
mem = cacheMemory(mem, addr, arch.PtrSize()*2)
|
||||
|
||||
// read len
|
||||
strlen, err := readIntRaw(mem, addr+uint64(arch.PtrSize()), int64(arch.PtrSize()))
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("could not read string len %s", err)
|
||||
}
|
||||
if strlen < 0 {
|
||||
return 0, 0, fmt.Errorf("invalid length: %d", strlen)
|
||||
var strlen int64
|
||||
var outaddr uint64
|
||||
var err error
|
||||
|
||||
for _, field := range typ.StructType.Field {
|
||||
switch field.Name {
|
||||
case "len":
|
||||
strlen, err = readIntRaw(mem, addr+uint64(field.ByteOffset), int64(arch.PtrSize()))
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("could not read string len %s", err)
|
||||
}
|
||||
if strlen < 0 {
|
||||
return 0, 0, fmt.Errorf("invalid length: %d", strlen)
|
||||
}
|
||||
case "str":
|
||||
outaddr, err = readUintRaw(mem, addr+uint64(field.ByteOffset), int64(arch.PtrSize()))
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("could not read string pointer %s", err)
|
||||
}
|
||||
if addr == 0 {
|
||||
return 0, 0, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read addr
|
||||
addr, err = readUintRaw(mem, addr, int64(arch.PtrSize()))
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("could not read string pointer %s", err)
|
||||
}
|
||||
if addr == 0 {
|
||||
return 0, 0, nil
|
||||
}
|
||||
return addr, strlen, nil
|
||||
return outaddr, strlen, nil
|
||||
}
|
||||
|
||||
func readStringValue(mem MemoryReadWriter, addr uint64, strlen int64, cfg LoadConfig) (string, error) {
|
||||
@ -2248,7 +2256,7 @@ func (v *Variable) readInterface() (_type, data *Variable, isnil bool) {
|
||||
|
||||
// +rtype -field iface.tab *itab
|
||||
// +rtype -field iface.data unsafe.Pointer
|
||||
// +rtype -field eface._type *_type
|
||||
// +rtype -field eface._type *_type|*internal/abi.Type
|
||||
// +rtype -field eface.data unsafe.Pointer
|
||||
|
||||
for _, f := range ityp.Field {
|
||||
@ -2259,7 +2267,7 @@ func (v *Variable) readInterface() (_type, data *Variable, isnil bool) {
|
||||
isnil = tab.Addr == 0
|
||||
if !isnil {
|
||||
var err error
|
||||
_type, err = tab.structMember("_type") // +rtype *_type
|
||||
_type, err = tab.structMember("_type") // +rtype *_type|*internal/abi.Type
|
||||
if err != nil {
|
||||
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
|
||||
return
|
||||
|
@ -212,7 +212,7 @@ func TestSetVariable(t *testing.T) {
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
assertVariable(t, variable, varTest{tc.name, true, tc.startVal, "", tc.typ, nil})
|
||||
|
||||
assertNoError(setVariable(p, tc.name, tc.expr), t, "SetVariable()")
|
||||
assertNoError(setVariable(p, tc.name, tc.expr), t, fmt.Sprintf("SetVariable(%q, %q)", tc.name, tc.expr))
|
||||
|
||||
variable, err = evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
@ -856,6 +856,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
assertNoError(grp.Continue(), t, "Continue() returned an error")
|
||||
for i, tc := range testcases {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
t.Logf("%q", tc.name)
|
||||
variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
|
||||
if err != nil && err.Error() == "evaluating methods not supported on this version of Go" {
|
||||
// this type of eval is unsupported with the current version of Go.
|
||||
|
Loading…
Reference in New Issue
Block a user