Skip to content

Commit

Permalink
proc: use DW_AT_trampoline to detect auto-generated code (#3528)
Browse files Browse the repository at this point in the history
Use the trampoline attribute to detect auto-generated code. This fixes
a bug where stepping into a method of a generic type called through an
interface will take the debugger into an auto-generated wrapper that
does not have a dictionary and using next will step out of the wrapper.

Fixes a bug reported on the #delve channel of the gophers slack server.
  • Loading branch information
aarzilli committed Oct 16, 2023
1 parent 04bb7fd commit 788df88
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
25 changes: 25 additions & 0 deletions _fixtures/genericintoiface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import "fmt"

type Blah[T any] struct {
x T
}

func (b *Blah[T]) F(y T) {
b.x = y
}

type BlahInt interface {
F(int)
}

func callf(b BlahInt) {
b.F(2)
fmt.Println(b)
}

func main() {
b := &Blah[int]{10}
callf(b)
}
41 changes: 41 additions & 0 deletions pkg/proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ const (
contReverseStep
contReverseStepout
contContinueToBreakpoint
contNothing
)

type seqTest struct {
Expand Down Expand Up @@ -531,6 +532,8 @@ func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *te
assertNoError(grp.Continue(), t, "Continue() returned an error")
err := p.ClearBreakpoint(bp.Addr)
assertNoError(err, t, "ClearBreakpoint() returned an error")
case contNothing:
// do nothing
}

f, ln = currentLineNumber(p, t)
Expand All @@ -552,6 +555,10 @@ func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *te
if !strings.HasSuffix(f, v[0]) || (ln != tgtln) {
t.Fatalf("Program did not continue to correct next location, expected %s was %s:%d (%#x) (testcase %d)", pos, filepath.Base(f), ln, pc, i)
}
case func(*proc.Target):
pos(p)
default:
panic(fmt.Errorf("unexpected type %T", pos))
}
}

Expand Down Expand Up @@ -6262,3 +6269,37 @@ func TestWaitForAttach(t *testing.T) {

cmd.Wait()
}

func TestNextGenericMethodThroughInterface(t *testing.T) {
// Tests that autogenerated wrappers for generic methods called through an
// interface are skipped.

varcheck := func(p *proc.Target) {
yvar := evalVariable(p, t, "y")
yval, _ := constant.Int64Val(yvar.Value)
if yval != 2 {
t.Errorf("expected 2 got %#v", yvar.Value)
}
}

if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
testseq2(t, "genericintoiface", "main.callf", []seqTest{
{contContinue, 17},
{contStep, 18},
{contStep, 10},
{contNothing, varcheck},
{contNext, 11},
{contNext, 19},
})
} else {
testseq2(t, "genericintoiface", "main.callf", []seqTest{
{contContinue, 17},
{contStep, 18},
{contStep, 9},
{contNext, 10},
{contNothing, varcheck},
{contNext, 11},
{contNext, 19},
})
}
}
2 changes: 1 addition & 1 deletion pkg/proc/target_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ func allowDuplicateBreakpoint(bp *Breakpoint, err error) (*Breakpoint, error) {
}

func isAutogenerated(loc Location) bool {
return loc.File == "<autogenerated>" && loc.Line == 1
return (loc.File == "<autogenerated>" && loc.Line == 1) || (loc.Fn != nil && loc.Fn.trampoline)
}

func isAutogeneratedOrDeferReturn(loc Location) bool {
Expand Down
2 changes: 1 addition & 1 deletion pkg/proc/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,7 @@ func extractVarInfoFromEntry(tgt *Target, bi *BinaryInfo, image *Image, regs op.
t, err = resolveParametricType(bi, mem, t, dictAddr)
if err != nil {
// Log the error, keep going with t, which will be the shape type
logflags.DebuggerLogger().Errorf("could not resolve parametric type of %s", n)
logflags.DebuggerLogger().Errorf("could not resolve parametric type of %s: %v", n, err)
}

addr, pieces, descr, err := bi.Location(entry, dwarf.AttrLocation, regs.PC(), regs, mem)
Expand Down

0 comments on commit 788df88

Please sign in to comment.