proc: step into unexported runtime funcs when already inside runtime (#2061)

Normally we don't step into unexported runtime functions because the
compiler is free to insert them into the code and they are not relevant
to the user, however if we are already stepping through a runtime
function we should let step into work normally and step into other
runtime functions.
This commit is contained in:
Alessandro Arzilli 2020-06-05 19:29:28 +02:00 committed by GitHub
parent 80b5b95182
commit 292f5c69f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,6 +7,7 @@ import (
"go/ast" "go/ast"
"go/token" "go/token"
"path/filepath" "path/filepath"
"strings"
"github.com/go-delve/delve/pkg/astutil" "github.com/go-delve/delve/pkg/astutil"
"github.com/go-delve/delve/pkg/dwarf/reader" "github.com/go-delve/delve/pkg/dwarf/reader"
@ -146,10 +147,17 @@ func (dbp *Target) Continue() error {
} }
if dbp.GetDirection() == Forward { if dbp.GetDirection() == Forward {
text, err := disassembleCurrentInstruction(dbp, curthread) text, err := disassembleCurrentInstruction(dbp, curthread)
if err != nil {
return err
}
var fn *Function
if loc, _ := curthread.Location(); loc != nil {
fn = loc.Fn
}
// here we either set a breakpoint into the destination of the CALL // here we either set a breakpoint into the destination of the CALL
// instruction or we determined that the called function is hidden, // instruction or we determined that the called function is hidden,
// either way we need to resume execution // either way we need to resume execution
if err = setStepIntoBreakpoint(dbp, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil { if err = setStepIntoBreakpoint(dbp, fn, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
return err return err
} }
} else { } else {
@ -513,7 +521,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
sameFrameCond := astutil.And(sameGCond, frameoffCondition(&topframe)) sameFrameCond := astutil.And(sameGCond, frameoffCondition(&topframe))
if stepInto && !backward { if stepInto && !backward {
err := setStepIntoBreakpoints(dbp, text, topframe, sameGCond) err := setStepIntoBreakpoints(dbp, topframe.Current.Fn, text, topframe, sameGCond)
if err != nil { if err != nil {
return err return err
} }
@ -625,14 +633,14 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {
return nil return nil
} }
func setStepIntoBreakpoints(dbp *Target, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error { func setStepIntoBreakpoints(dbp *Target, curfn *Function, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
for _, instr := range text { for _, instr := range text {
if instr.Loc.File != topframe.Current.File || instr.Loc.Line != topframe.Current.Line || !instr.IsCall() { if instr.Loc.File != topframe.Current.File || instr.Loc.Line != topframe.Current.Line || !instr.IsCall() {
continue continue
} }
if instr.DestLoc != nil { if instr.DestLoc != nil {
if err := setStepIntoBreakpoint(dbp, []AsmInstruction{instr}, sameGCond); err != nil { if err := setStepIntoBreakpoint(dbp, curfn, []AsmInstruction{instr}, sameGCond); err != nil {
return err return err
} }
} else { } else {
@ -708,11 +716,16 @@ func removePCsBetween(pcs []uint64, start, end uint64) []uint64 {
return out return out
} }
func setStepIntoBreakpoint(dbp *Target, text []AsmInstruction, cond ast.Expr) error { func setStepIntoBreakpoint(dbp *Target, curfn *Function, text []AsmInstruction, cond ast.Expr) error {
if len(text) <= 0 { if len(text) <= 0 {
return nil return nil
} }
// If the current function is already a runtime function then
// setStepIntoBreakpoint is allowed to step into unexported runtime
// functions.
stepIntoUnexportedRuntime := curfn != nil && strings.HasPrefix(curfn.Name, "runtime.")
instr := text[0] instr := text[0]
if instr.DestLoc == nil { if instr.DestLoc == nil {
@ -724,7 +737,7 @@ func setStepIntoBreakpoint(dbp *Target, text []AsmInstruction, cond ast.Expr) er
fn := instr.DestLoc.Fn fn := instr.DestLoc.Fn
// Skip unexported runtime functions // Skip unexported runtime functions
if fn != nil && fn.privateRuntime() { if !stepIntoUnexportedRuntime && fn != nil && fn.privateRuntime() {
return nil return nil
} }