Ensure thread is stopped before setting breakpoint

For hardware breakpoints we have to set them on every thread. It could
be the case that another thread is running. Stop it first, set the
breakpoint, then continue it.
This commit is contained in:
Derek Parker
2015-06-24 09:29:16 -05:00
parent 7c8fd02685
commit b35a743a3c
5 changed files with 23 additions and 5 deletions

View File

@ -90,8 +90,15 @@ func (dbp *Process) setBreakpoint(tid int, addr uint64, temp bool) (*Breakpoint,
if used { if used {
continue continue
} }
for t, _ := range dbp.Threads { for tid, t := range dbp.Threads {
if err := dbp.setHardwareBreakpoint(i, t, addr); err != nil { if t.running {
err := t.Halt()
if err != nil {
return nil, err
}
defer t.Continue()
}
if err := dbp.setHardwareBreakpoint(i, tid, addr); err != nil {
return nil, fmt.Errorf("could not set hardware breakpoint on thread %d: %s", t, err) return nil, fmt.Errorf("could not set hardware breakpoint on thread %d: %s", t, err)
} }
} }

View File

@ -271,12 +271,15 @@ func (dbp *Process) trapWait(pid int) (*Thread, error) {
continue continue
} }
if status.StopSignal() == sys.SIGTRAP { if status.StopSignal() == sys.SIGTRAP {
th.running = false
return dbp.handleBreakpointOnThread(wpid) return dbp.handleBreakpointOnThread(wpid)
} }
if status.StopSignal() == sys.SIGTRAP && dbp.halt { if status.StopSignal() == sys.SIGTRAP && dbp.halt {
th.running = false
return th, nil return th, nil
} }
if status.StopSignal() == sys.SIGSTOP && dbp.halt { if status.StopSignal() == sys.SIGSTOP && dbp.halt {
th.running = false
return nil, ManualStopError{} return nil, ManualStopError{}
} }
if th != nil { if th != nil {

View File

@ -65,7 +65,11 @@ func (thread *Thread) Continue() error {
// Otherwise we simply execute the next instruction. // Otherwise we simply execute the next instruction.
func (thread *Thread) Step() (err error) { func (thread *Thread) Step() (err error) {
thread.singleStepping = true thread.singleStepping = true
defer func() { thread.singleStepping = false }() thread.running = true
defer func() {
thread.singleStepping = false
thread.running = false
}()
pc, err := thread.PC() pc, err := thread.PC()
if err != nil { if err != nil {
return err return err

View File

@ -18,6 +18,7 @@ func (t *Thread) Halt() error {
if kret != C.KERN_SUCCESS { if kret != C.KERN_SUCCESS {
return fmt.Errorf("could not suspend thread %d", t.Id) return fmt.Errorf("could not suspend thread %d", t.Id)
} }
t.running = false
return nil return nil
} }
@ -35,6 +36,7 @@ func (t *Thread) singleStep() error {
} }
func (t *Thread) resume() error { func (t *Thread) resume() error {
t.running = true
// TODO(dp) set flag for ptrace stops // TODO(dp) set flag for ptrace stops
var err error var err error
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.Pid, 0) }) t.dbp.execPtraceFunc(func() { err = PtraceCont(t.dbp.Pid, 0) })

View File

@ -18,16 +18,18 @@ func (t *Thread) Halt() error {
} }
err := sys.Tgkill(t.dbp.Pid, t.Id, sys.SIGSTOP) err := sys.Tgkill(t.dbp.Pid, t.Id, sys.SIGSTOP)
if err != nil { if err != nil {
return fmt.Errorf("Halt err %s %d", err, t.Id) return fmt.Errorf("halt err %s on thread %d", err, t.Id)
} }
_, _, err = wait(t.Id, 0) _, _, err = wait(t.Id, 0)
if err != nil { if err != nil {
return fmt.Errorf("wait err %s %d", err, t.Id) return fmt.Errorf("wait err %s on thread %d", err, t.Id)
} }
t.running = false
return nil return nil
} }
func (t *Thread) resume() (err error) { func (t *Thread) resume() (err error) {
t.running = true
t.dbp.execPtraceFunc(func() { err = PtraceCont(t.Id, 0) }) t.dbp.execPtraceFunc(func() { err = PtraceCont(t.Id, 0) })
return return
} }