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 {
|
func (p *Process) StepInstruction() error {
|
||||||
if p.selectedGoroutine == nil {
|
thread := p.currentThread
|
||||||
return errors.New("cannot single step: no selected goroutine")
|
if p.selectedGoroutine != nil {
|
||||||
}
|
if p.selectedGoroutine.Thread == nil {
|
||||||
if p.selectedGoroutine.Thread == nil {
|
if _, err := p.SetBreakpoint(p.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(p.selectedGoroutine)); err != nil {
|
||||||
if _, err := p.SetBreakpoint(p.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(p.selectedGoroutine)); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
|
return proc.Continue(p)
|
||||||
}
|
}
|
||||||
return proc.Continue(p)
|
thread = p.selectedGoroutine.Thread.(*Thread)
|
||||||
}
|
}
|
||||||
p.allGCache = nil
|
p.allGCache = nil
|
||||||
if p.exited {
|
if p.exited {
|
||||||
return &proc.ProcessExitedError{Pid: p.conn.pid}
|
return &proc.ProcessExitedError{Pid: p.conn.pid}
|
||||||
}
|
}
|
||||||
p.selectedGoroutine.Thread.(*Thread).clearBreakpointState()
|
thread.clearBreakpointState()
|
||||||
err := p.selectedGoroutine.Thread.(*Thread).StepInstruction()
|
err := thread.StepInstruction()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return p.selectedGoroutine.Thread.(*Thread).SetCurrentBreakpoint()
|
return thread.SetCurrentBreakpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Process) SwitchThread(tid int) error {
|
func (p *Process) SwitchThread(tid int) error {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package native
|
package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"os"
|
"os"
|
||||||
@ -297,26 +296,27 @@ func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
|||||||
// asssociated with the selected goroutine. All other
|
// asssociated with the selected goroutine. All other
|
||||||
// threads will remain stopped.
|
// threads will remain stopped.
|
||||||
func (dbp *Process) StepInstruction() (err error) {
|
func (dbp *Process) StepInstruction() (err error) {
|
||||||
if dbp.selectedGoroutine == nil {
|
thread := dbp.currentThread
|
||||||
return errors.New("cannot single step: no selected goroutine")
|
if dbp.selectedGoroutine != nil {
|
||||||
}
|
if dbp.selectedGoroutine.Thread == nil {
|
||||||
if dbp.selectedGoroutine.Thread == nil {
|
// Step called on parked goroutine
|
||||||
// Step called on parked goroutine
|
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
||||||
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, proc.NextBreakpoint, proc.SameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
|
return proc.Continue(dbp)
|
||||||
}
|
}
|
||||||
return proc.Continue(dbp)
|
thread = dbp.selectedGoroutine.Thread.(*Thread)
|
||||||
}
|
}
|
||||||
dbp.allGCache = nil
|
dbp.allGCache = nil
|
||||||
if dbp.exited {
|
if dbp.exited {
|
||||||
return &proc.ProcessExitedError{}
|
return &proc.ProcessExitedError{}
|
||||||
}
|
}
|
||||||
dbp.selectedGoroutine.Thread.(*Thread).clearBreakpointState()
|
thread.clearBreakpointState()
|
||||||
err = dbp.selectedGoroutine.Thread.(*Thread).StepInstruction()
|
err = thread.StepInstruction()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return dbp.selectedGoroutine.Thread.(*Thread).SetCurrentBreakpoint()
|
return thread.SetCurrentBreakpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SwitchThread changes from current thread to the thread specified by `tid`.
|
// SwitchThread changes from current thread to the thread specified by `tid`.
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/derekparker/delve/pkg/dwarf/frame"
|
||||||
"github.com/derekparker/delve/pkg/proc"
|
"github.com/derekparker/delve/pkg/proc"
|
||||||
"github.com/derekparker/delve/pkg/proc/gdbserial"
|
"github.com/derekparker/delve/pkg/proc/gdbserial"
|
||||||
"github.com/derekparker/delve/pkg/proc/native"
|
"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