diff --git a/proc/proc_test.go b/proc/proc_test.go index 5f51496d..44179e41 100644 --- a/proc/proc_test.go +++ b/proc/proc_test.go @@ -1556,3 +1556,23 @@ func TestIssue396(t *testing.T) { assertNoError(err, t, "FindFunctionLocation()") }) } + +func TestIssue414(t *testing.T) { + // Stepping until the program exits + withTestProcess("math", t, func(p *Process, fixture protest.Fixture) { + start, _, err := p.goSymTable.LineToPC(fixture.Source, 9) + assertNoError(err, t, "LineToPC()") + _, err = p.SetBreakpoint(start) + assertNoError(err, t, "SetBreakpoint()") + assertNoError(p.Continue(), t, "Continue()") + for { + err := p.Step() + if err != nil { + if _, exited := err.(ProcessExitedError); exited { + break + } + } + assertNoError(err, t, "Step()") + } + }) +} diff --git a/proc/threads.go b/proc/threads.go index ff46d146..d3904b55 100644 --- a/proc/threads.go +++ b/proc/threads.go @@ -95,6 +95,9 @@ func (thread *Thread) StepInstruction() (err error) { err = thread.singleStep() if err != nil { + if _, exited := err.(ProcessExitedError); exited { + return err + } return fmt.Errorf("step failed: %s", err.Error()) } return nil diff --git a/proc/threads_darwin.go b/proc/threads_darwin.go index 126caa69..0c79d61e 100644 --- a/proc/threads_darwin.go +++ b/proc/threads_darwin.go @@ -39,8 +39,11 @@ func (t *Thread) singleStep() error { return fmt.Errorf("could not single step") } for { - port := C.mach_port_wait(t.dbp.os.portSet, C.int(0)) - if port == C.mach_port_t(t.ID) { + twthread, err := t.dbp.trapWait(t.dbp.Pid) + if err != nil { + return err + } + if twthread.ID == t.ID { break } } diff --git a/proc/threads_linux.go b/proc/threads_linux.go index f1d649db..de29963b 100644 --- a/proc/threads_linux.go +++ b/proc/threads_linux.go @@ -53,6 +53,14 @@ func (t *Thread) singleStep() (err error) { if err != nil { return err } + if (status == nil || status.Exited()) && wpid == t.dbp.Pid { + t.dbp.postExit() + rs := 0 + if status != nil { + rs = status.ExitStatus() + } + return ProcessExitedError{Pid: t.dbp.Pid, Status: rs} + } if wpid == t.ID && status.StopSignal() == sys.SIGTRAP { return nil } diff --git a/proc/threads_windows.go b/proc/threads_windows.go index 94ced6cd..d61a1bbf 100644 --- a/proc/threads_windows.go +++ b/proc/threads_windows.go @@ -1,7 +1,6 @@ package proc import ( - "fmt" "syscall" sys "golang.org/x/sys/windows" @@ -48,10 +47,7 @@ func (t *Thread) singleStep() error { if thread.ID == t.ID { continue } - _, err := _SuspendThread(thread.os.hThread) - if err != nil { - return fmt.Errorf("could not suspend thread: %d: %v", thread.ID, err) - } + _, _ = _SuspendThread(thread.os.hThread) } // Continue and wait for the step to complete @@ -72,10 +68,7 @@ func (t *Thread) singleStep() error { if thread.ID == t.ID { continue } - _, err := _ResumeThread(thread.os.hThread) - if err != nil { - return fmt.Errorf("could not resume thread: %d: %v", thread.ID, err) - } + _, _ = _ResumeThread(thread.os.hThread) } // Unset the processor TRAP flag