From 39274f6028b38e7b7b674e84bf96694080e537fe Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Fri, 23 Jul 2021 18:21:24 +0200 Subject: [PATCH] proc: make moduleDataToImage more robust (#2613) Conversion form a moduledata object into an image object was implemented by looking for a function covering the start address of the text section of the moduledata object, and then converting that into its corresponding image. Unfortunately this seems to not always work. In particular it does not work on linux/386 with go1.17 (but it might also fail on other combinations): the start address of the text section is, for whatever reason, not part of any function. As a fallback simply scan all images we know of and return the closest one that has start address less than or equal to the start address of the text section we are looking for. Fixes TestPluginVariables on go1.17/linux/386. Fixes #2611 Co-authored-by: a --- pkg/proc/bininfo.go | 18 ++++++++++++++++-- pkg/proc/types.go | 20 +++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index c2b1a5cc..991a18f5 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -715,14 +715,28 @@ func (bi *BinaryInfo) AddImage(path string, addr uint64) error { // moduleDataToImage finds the image corresponding to the given module data object. func (bi *BinaryInfo) moduleDataToImage(md *moduleData) *Image { - return bi.funcToImage(bi.PCToFunc(uint64(md.text))) + fn := bi.PCToFunc(uint64(md.text)) + if fn != nil { + return bi.funcToImage(fn) + } + // Try searching for the image with the closest address preceding md.text + var so *Image + for i := range bi.Images { + if bi.Images[i].StaticBase > md.text { + continue + } + if so == nil || bi.Images[i].StaticBase > so.StaticBase { + so = bi.Images[i] + } + } + return so } // imageToModuleData finds the module data in mds corresponding to the given image. func (bi *BinaryInfo) imageToModuleData(image *Image, mds []moduleData) *moduleData { for _, md := range mds { im2 := bi.moduleDataToImage(&md) - if im2.index == image.index { + if im2 != nil && im2.index == image.index { return &md } } diff --git a/pkg/proc/types.go b/pkg/proc/types.go index d052b61d..deb9c434 100644 --- a/pkg/proc/types.go +++ b/pkg/proc/types.go @@ -134,17 +134,19 @@ func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind md := findModuleDataForType(bi, mds, _type.Addr, _type.mem) if md != nil { so := bi.moduleDataToImage(md) - if rtdie, ok := so.runtimeTypeToDIE[uint64(_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) - } - if rtdie.kind == -1 { - if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { - rtdie.kind, _ = constant.Int64Val(kindField.Value) + if so != nil { + if rtdie, ok := so.runtimeTypeToDIE[uint64(_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) } + if rtdie.kind == -1 { + if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { + rtdie.kind, _ = constant.Int64Val(kindField.Value) + } + } + return typ, rtdie.kind, nil } - return typ, rtdie.kind, nil } }