proc: Continue does not work with breakpoints set on NOP (OSX)
Fixes #262
This commit is contained in:
parent
708cf2f290
commit
b21686e6c4
@ -11,7 +11,7 @@ func demo(id int, wait *sync.WaitGroup) {
|
|||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
sleep := rand.Intn(10) + 1
|
sleep := rand.Intn(10) + 1
|
||||||
fmt.Printf("id: %d step: %d sleeping %d\n", id, i, sleep)
|
fmt.Printf("id: %d step: %d sleeping %d\n", id, i, sleep)
|
||||||
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
wait.Done()
|
wait.Done()
|
||||||
|
16
_fixtures/issue262.go
Normal file
16
_fixtures/issue262.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func typicalFunction() (res int) {
|
||||||
|
defer func() {
|
||||||
|
res = 2
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
res = 10
|
||||||
|
return // setup breakpoint here
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(typicalFunction())
|
||||||
|
}
|
@ -329,5 +329,13 @@ func (dbp *Process) wait(pid, options int) (int, *sys.WaitStatus, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dbp *Process) exitGuard(err error) error {
|
func (dbp *Process) exitGuard(err error) error {
|
||||||
|
if err != ErrContinueThread {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, status, werr := dbp.wait(dbp.Pid, sys.WNOHANG)
|
||||||
|
if werr == nil && status.Exited() {
|
||||||
|
dbp.postExit()
|
||||||
|
return ProcessExitedError{Pid: dbp.Pid, Status: status.ExitStatus()}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -953,7 +953,7 @@ func TestFrameEvaluation(t *testing.T) {
|
|||||||
assertNoError(err, t, "setFunctionBreakpoint")
|
assertNoError(err, t, "setFunctionBreakpoint")
|
||||||
assertNoError(p.Continue(), t, "Continue()")
|
assertNoError(p.Continue(), t, "Continue()")
|
||||||
|
|
||||||
/**** Testing evaluation on goroutines ****/
|
// Testing evaluation on goroutines
|
||||||
gs, err := p.GoroutinesInfo()
|
gs, err := p.GoroutinesInfo()
|
||||||
assertNoError(err, t, "GoroutinesInfo")
|
assertNoError(err, t, "GoroutinesInfo")
|
||||||
found := make([]bool, 10)
|
found := make([]bool, 10)
|
||||||
@ -992,7 +992,7 @@ func TestFrameEvaluation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** Testing evaluation on frames ****/
|
// Testing evaluation on frames
|
||||||
assertNoError(p.Continue(), t, "Continue() 2")
|
assertNoError(p.Continue(), t, "Continue() 2")
|
||||||
g, err := p.CurrentThread.GetG()
|
g, err := p.CurrentThread.GetG()
|
||||||
assertNoError(err, t, "GetG()")
|
assertNoError(err, t, "GetG()")
|
||||||
@ -1129,3 +1129,23 @@ func TestBreakpointCounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue262(t *testing.T) {
|
||||||
|
// Continue does not work when the current breakpoint is set on a NOP instruction
|
||||||
|
withTestProcess("issue262", t, func(p *Process, fixture protest.Fixture) {
|
||||||
|
addr, _, err := p.goSymTable.LineToPC(fixture.Source, 11)
|
||||||
|
assertNoError(err, t, "LineToPC")
|
||||||
|
_, err = p.SetBreakpoint(addr)
|
||||||
|
assertNoError(err, t, "SetBreakpoint()")
|
||||||
|
|
||||||
|
assertNoError(p.Continue(), t, "Continue()")
|
||||||
|
err = p.Continue()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("No error on second continue")
|
||||||
|
}
|
||||||
|
_, exited := err.(ProcessExitedError)
|
||||||
|
if !exited {
|
||||||
|
t.Fatalf("Process did not exit after second continue: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package proc
|
package proc
|
||||||
|
|
||||||
// #include "threads_darwin.h"
|
// #include "threads_darwin.h"
|
||||||
|
// #include "proc_darwin.h"
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -12,6 +13,8 @@ type OSSpecificDetails struct {
|
|||||||
registers C.x86_thread_state64_t
|
registers C.x86_thread_state64_t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrContinueThread = fmt.Errorf("could not continue thread")
|
||||||
|
|
||||||
func (t *Thread) halt() (err error) {
|
func (t *Thread) halt() (err error) {
|
||||||
kret := C.thread_suspend(t.os.thread_act)
|
kret := C.thread_suspend(t.os.thread_act)
|
||||||
if kret != C.KERN_SUCCESS {
|
if kret != C.KERN_SUCCESS {
|
||||||
@ -27,7 +30,13 @@ func (t *Thread) singleStep() error {
|
|||||||
if kret != C.KERN_SUCCESS {
|
if kret != C.KERN_SUCCESS {
|
||||||
return fmt.Errorf("could not single step")
|
return fmt.Errorf("could not single step")
|
||||||
}
|
}
|
||||||
t.dbp.trapWait(0)
|
for {
|
||||||
|
port := C.mach_port_wait(t.dbp.os.portSet)
|
||||||
|
if port == C.mach_port_t(t.Id) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kret = C.clear_trap_flag(t.os.thread_act)
|
kret = C.clear_trap_flag(t.os.thread_act)
|
||||||
if kret != C.KERN_SUCCESS {
|
if kret != C.KERN_SUCCESS {
|
||||||
return fmt.Errorf("could not clear CPU trap flag")
|
return fmt.Errorf("could not clear CPU trap flag")
|
||||||
@ -45,7 +54,7 @@ func (t *Thread) resume() error {
|
|||||||
}
|
}
|
||||||
kret := C.resume_thread(t.os.thread_act)
|
kret := C.resume_thread(t.os.thread_act)
|
||||||
if kret != C.KERN_SUCCESS {
|
if kret != C.KERN_SUCCESS {
|
||||||
return fmt.Errorf("could not continue thread")
|
return ErrContinueThread
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user