Skip to content

Commit

Permalink
pkg/proc: handle double inlined calls (go-delve#2880)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
derekparker authored Jan 24, 2022
1 parent 0005eb9 commit 8ddb64c
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
26 changes: 26 additions & 0 deletions _fixtures/doubleinline.go
Original file line number Diff line number Diff line change
@@ -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())
}
4 changes: 4 additions & 0 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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")
Expand Down

0 comments on commit 8ddb64c

Please sign in to comment.