pkg/proc: handle double inlined calls (#2880)

It's possible that an inlined function call also contains an inlined
sunroutine. In this case we should also parse the children of
inlined calls to ensure we don't lose this information.
This commit is contained in:
Derek Parker 2022-01-23 23:56:37 -08:00 committed by GitHub
parent 0005eb9f58
commit 8ddb64c808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 0 deletions

26
_fixtures/doubleinline.go Normal file

@ -0,0 +1,26 @@
package main
import (
"fmt"
"runtime"
"strconv"
)
type Rectangle struct{}
func (r *Rectangle) Height() int {
h, _ := strconv.ParseInt("7", 10, 0)
return int(h)
}
func (r *Rectangle) Width() int {
return 6
}
func (r *Rectangle) Area() int { return r.Height() * r.Width() }
func main() {
var r Rectangle
runtime.Breakpoint()
fmt.Println(r.Area())
}

@ -2262,6 +2262,10 @@ func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsConte
fl := fileLine{callfile, int(callline)}
bi.inlinedCallLines[fl] = append(bi.inlinedCallLines[fl], lowpc)
if entry.Children {
bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
}
}
reader.SkipChildren()
}

@ -3979,6 +3979,9 @@ func TestInlineBreakpoint(t *testing.T) {
}
withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) {
pcs, err := proc.FindFileLocation(p, fixture.Source, 17)
if err != nil {
t.Fatal(err)
}
t.Logf("%#v\n", pcs)
if len(pcs) != 1 {
t.Fatalf("unable to get PC for inlined function call: %v", pcs)
@ -3995,6 +3998,27 @@ func TestInlineBreakpoint(t *testing.T) {
})
}
func TestDoubleInlineBreakpoint(t *testing.T) {
// We should be able to set a breakpoint on an inlined function that
// has been inlined within an inlined function.
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
// Versions of go before 1.10 do not have DWARF information for inlined calls
t.Skip("inlining not supported")
}
withTestProcessArgs("doubleinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) {
fns, err := p.BinInfo().FindFunction("main.(*Rectangle).Height")
if err != nil {
t.Fatal(err)
}
if len(fns) != 1 {
t.Fatalf("expected one function for Height, got %d", len(fns))
}
if len(fns[0].InlinedCalls) != 1 {
t.Fatalf("expected one inlined call for Height, got %d", len(fns[0].InlinedCalls))
}
})
}
func TestIssue951(t *testing.T) {
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
t.Skip("scopes not implemented in <=go1.8")