proc/native, proc/gdbserial: StepInstruction without goroutine
proc.Process.StepInstruction should work even if there is no goroutine selected.
This commit is contained in:
parent
e9e0830054
commit
5c2673a632
@ -623,25 +623,26 @@ continueLoop:
|
||||
}
|
||||
|
||||
func (p *Process) StepInstruction() error {
|
||||
if p.selectedGoroutine == nil {
|
||||
return errors.New("cannot single step: no selected goroutine")
|
||||
}
|
||||
if p.selectedGoroutine.Thread == nil {
|
||||
if _, err := p.SetBreakpoint(p.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(p.selectedGoroutine)); err != nil {
|
||||
return err
|
||||
thread := p.currentThread
|
||||
if p.selectedGoroutine != nil {
|
||||
if p.selectedGoroutine.Thread == nil {
|
||||
if _, err := p.SetBreakpoint(p.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(p.selectedGoroutine)); err != nil {
|
||||
return err
|
||||
}
|
||||
return proc.Continue(p)
|
||||
}
|
||||
return proc.Continue(p)
|
||||
thread = p.selectedGoroutine.Thread.(*Thread)
|
||||
}
|
||||
p.allGCache = nil
|
||||
if p.exited {
|
||||
return &proc.ProcessExitedError{Pid: p.conn.pid}
|
||||
}
|
||||
p.selectedGoroutine.Thread.(*Thread).clearBreakpointState()
|
||||
err := p.selectedGoroutine.Thread.(*Thread).StepInstruction()
|
||||
thread.clearBreakpointState()
|
||||
err := thread.StepInstruction()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.selectedGoroutine.Thread.(*Thread).SetCurrentBreakpoint()
|
||||
return thread.SetCurrentBreakpoint()
|
||||
}
|
||||
|
||||
func (p *Process) SwitchThread(tid int) error {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"os"
|
||||
@ -297,26 +296,27 @@ func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
||||
// asssociated with the selected goroutine. All other
|
||||
// threads will remain stopped.
|
||||
func (dbp *Process) StepInstruction() (err error) {
|
||||
if dbp.selectedGoroutine == nil {
|
||||
return errors.New("cannot single step: no selected goroutine")
|
||||
}
|
||||
if dbp.selectedGoroutine.Thread == nil {
|
||||
// Step called on parked goroutine
|
||||
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
||||
return err
|
||||
thread := dbp.currentThread
|
||||
if dbp.selectedGoroutine != nil {
|
||||
if dbp.selectedGoroutine.Thread == nil {
|
||||
// Step called on parked goroutine
|
||||
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
||||
return err
|
||||
}
|
||||
return proc.Continue(dbp)
|
||||
}
|
||||
return proc.Continue(dbp)
|
||||
thread = dbp.selectedGoroutine.Thread.(*Thread)
|
||||
}
|
||||
dbp.allGCache = nil
|
||||
if dbp.exited {
|
||||
return &proc.ProcessExitedError{}
|
||||
}
|
||||
dbp.selectedGoroutine.Thread.(*Thread).clearBreakpointState()
|
||||
err = dbp.selectedGoroutine.Thread.(*Thread).StepInstruction()
|
||||
thread.clearBreakpointState()
|
||||
err = thread.StepInstruction()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dbp.selectedGoroutine.Thread.(*Thread).SetCurrentBreakpoint()
|
||||
return thread.SetCurrentBreakpoint()
|
||||
}
|
||||
|
||||
// SwitchThread changes from current thread to the thread specified by `tid`.
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/derekparker/delve/pkg/dwarf/frame"
|
||||
"github.com/derekparker/delve/pkg/proc"
|
||||
"github.com/derekparker/delve/pkg/proc/gdbserial"
|
||||
"github.com/derekparker/delve/pkg/proc/native"
|
||||
@ -2954,3 +2955,29 @@ func TestIssue877(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIssue893(t *testing.T) {
|
||||
// Test what happens when next is called immediately after launching the
|
||||
// executable, acceptable behaviors are: (a) no error, (b) no source at PC
|
||||
// error.
|
||||
protest.AllowRecording(t)
|
||||
withTestProcess("increment", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
err := proc.Next(p)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := err.(*frame.NoFDEForPCError); ok {
|
||||
return
|
||||
}
|
||||
assertNoError(err, t, "Next")
|
||||
})
|
||||
}
|
||||
|
||||
func TestStepInstructionNoGoroutine(t *testing.T) {
|
||||
protest.AllowRecording(t)
|
||||
withTestProcess("increment", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
// Call StepInstruction immediately after launching the program, it should
|
||||
// work even though no goroutine is selected.
|
||||
assertNoError(p.StepInstruction(), t, "StepInstruction")
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user