diff --git a/_fixtures/doubleinline.go b/_fixtures/doubleinline.go new file mode 100644 index 00000000..6a73c596 --- /dev/null +++ b/_fixtures/doubleinline.go @@ -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()) +} diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index 00ba6edb..4b93cbb1 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -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() } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 798aefc5..4b6825ba 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -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")