proc: simplify next/step/stepout condition code

Adds a library of utility functions to generated breakpoint conditions
for next, step and stepout.
This commit is contained in:
aarzilli
2020-03-25 12:37:15 +01:00
committed by Derek Parker
parent eac6ebed03
commit 7dedf1ed55
2 changed files with 48 additions and 44 deletions

40
pkg/astutil/astutil.go Normal file
View File

@ -0,0 +1,40 @@
// This package contains utility functions used by pkg/proc to generate
// ast.Expr expressions.
package astutil
import (
"go/ast"
"go/token"
"strconv"
)
// Eql returns an expression evaluating 'x == y'.
func Eql(x, y ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{Op: token.EQL, X: x, Y: y}
}
// Sel returns an expression evaluating 'x.sel'.
func Sel(x ast.Expr, sel string) *ast.SelectorExpr {
return &ast.SelectorExpr{X: x, Sel: &ast.Ident{Name: sel}}
}
// PkgVar returns an expression evaluating 'pkg.v'.
func PkgVar(pkg, v string) *ast.SelectorExpr {
return &ast.SelectorExpr{X: &ast.Ident{Name: pkg}, Sel: &ast.Ident{Name: v}}
}
// Int returns an expression representing the integer 'n'.
func Int(n int64) *ast.BasicLit {
return &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(n, 10)}
}
// And returns an expression evaluating 'x && y'.
func And(x, y ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{Op: token.LAND, X: x, Y: y}
}
// Or returns an expression evaluating 'x || y'.
func Or(x, y ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{Op: token.LOR, X: x, Y: y}
}

View File

@ -7,8 +7,8 @@ import (
"go/ast" "go/ast"
"go/token" "go/token"
"path/filepath" "path/filepath"
"strconv"
"github.com/go-delve/delve/pkg/astutil"
"github.com/go-delve/delve/pkg/dwarf/reader" "github.com/go-delve/delve/pkg/dwarf/reader"
) )
@ -289,39 +289,11 @@ func sameGoroutineCondition(g *G) ast.Expr {
if g == nil { if g == nil {
return nil return nil
} }
return &ast.BinaryExpr{ return astutil.Eql(astutil.Sel(astutil.PkgVar("runtime", "curg"), "goid"), astutil.Int(int64(g.ID)))
Op: token.EQL,
X: &ast.SelectorExpr{
X: &ast.SelectorExpr{
X: &ast.Ident{Name: "runtime"},
Sel: &ast.Ident{Name: "curg"},
},
Sel: &ast.Ident{Name: "goid"},
},
Y: &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(g.ID)},
}
} }
func frameoffCondition(frameoff int64) ast.Expr { func frameoffCondition(frame *Stackframe) ast.Expr {
return &ast.BinaryExpr{ return astutil.Eql(astutil.PkgVar("runtime", "frameoff"), astutil.Int(frame.FrameOffset()))
Op: token.EQL,
X: &ast.SelectorExpr{
X: &ast.Ident{Name: "runtime"},
Sel: &ast.Ident{Name: "frameoff"},
},
Y: &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(frameoff, 10)},
}
}
func andFrameoffCondition(cond ast.Expr, frameoff int64) ast.Expr {
if cond == nil {
return nil
}
return &ast.BinaryExpr{
Op: token.LAND,
X: cond,
Y: frameoffCondition(frameoff),
}
} }
// StepOut will continue until the current goroutine exits the // StepOut will continue until the current goroutine exits the
@ -384,7 +356,7 @@ func (dbp *Target) StepOut() error {
if topframe.Ret != 0 { if topframe.Ret != 0 {
topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe) topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe)
retFrameCond := andFrameoffCondition(sameGCond, retframe.FrameOffset()) retFrameCond := astutil.And(sameGCond, frameoffCondition(retframe))
bp, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(topframe.Ret, NextBreakpoint, retFrameCond)) bp, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(topframe.Ret, NextBreakpoint, retFrameCond))
if err != nil { if err != nil {
return err return err
@ -537,7 +509,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
return err return err
} }
sameFrameCond := andFrameoffCondition(sameGCond, topframe.FrameOffset()) sameFrameCond := astutil.And(sameGCond, frameoffCondition(&topframe))
if stepInto && !backward { if stepInto && !backward {
err := setStepIntoBreakpoints(dbp, text, topframe, sameGCond) err := setStepIntoBreakpoints(dbp, text, topframe, sameGCond)
@ -618,18 +590,10 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
if !topframe.Inlined { if !topframe.Inlined {
topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe) topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe)
retFrameCond := andFrameoffCondition(sameGCond, retframe.FrameOffset()) retFrameCond := astutil.And(sameGCond, frameoffCondition(retframe))
var sameOrRetFrameCond ast.Expr var sameOrRetFrameCond ast.Expr
if sameGCond != nil { if sameGCond != nil {
sameOrRetFrameCond = &ast.BinaryExpr{ sameOrRetFrameCond = astutil.And(sameGCond, astutil.Or(frameoffCondition(topframe), frameoffCondition(retframe)))
Op: token.LAND,
X: sameGCond,
Y: &ast.BinaryExpr{
Op: token.LOR,
X: frameoffCondition(topframe.FrameOffset()),
Y: frameoffCondition(retframe.FrameOffset()),
},
}
} }
// Add a breakpoint on the return address for the current frame. // Add a breakpoint on the return address for the current frame.