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 <a@kra>
This commit is contained in:
Alessandro Arzilli 2021-07-23 18:21:24 +02:00 committed by GitHub
parent f74b7a6e39
commit 39274f6028
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 11 deletions

@ -715,14 +715,28 @@ func (bi *BinaryInfo) AddImage(path string, addr uint64) error {
// moduleDataToImage finds the image corresponding to the given module data object. // moduleDataToImage finds the image corresponding to the given module data object.
func (bi *BinaryInfo) moduleDataToImage(md *moduleData) *Image { 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. // imageToModuleData finds the module data in mds corresponding to the given image.
func (bi *BinaryInfo) imageToModuleData(image *Image, mds []moduleData) *moduleData { func (bi *BinaryInfo) imageToModuleData(image *Image, mds []moduleData) *moduleData {
for _, md := range mds { for _, md := range mds {
im2 := bi.moduleDataToImage(&md) im2 := bi.moduleDataToImage(&md)
if im2.index == image.index { if im2 != nil && im2.index == image.index {
return &md return &md
} }
} }

@ -134,17 +134,19 @@ func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind
md := findModuleDataForType(bi, mds, _type.Addr, _type.mem) md := findModuleDataForType(bi, mds, _type.Addr, _type.mem)
if md != nil { if md != nil {
so := bi.moduleDataToImage(md) so := bi.moduleDataToImage(md)
if rtdie, ok := so.runtimeTypeToDIE[uint64(_type.Addr-md.types)]; ok { if so != nil {
typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache) if rtdie, ok := so.runtimeTypeToDIE[uint64(_type.Addr-md.types)]; ok {
if err != nil { typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache)
return nil, 0, fmt.Errorf("invalid interface type: %v", err) 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 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
} }
} }