提交 3fba1f71 编写于 作者: D Derek Parker

Correctly handle hardware breakpoints across threads

* Set hardware breakpoints on all existing threads
* Set hardware breakpoints on any new thread the spawns

Fixes #111
上级 d66dfbef
// fix lines
package main
import (
"fmt"
"runtime"
"time"
)
......@@ -46,3 +46,8 @@ func main() {
func testgoroutine(foo int, d chan int) {
d <- foo
}
func init() {
runtime.LockOSThread()
runtime.GOMAXPROCS(4)
}
......@@ -120,8 +120,10 @@ func (dbp *DebuggedProcess) setBreakpoint(tid int, addr uint64, temp bool) (*Bre
break
}
if v == nil {
if err := setHardwareBreakpoint(i, tid, addr); err != nil {
return nil, fmt.Errorf("could not set hardware breakpoint: %v", err)
for t, _ := range dbp.Threads {
if err := setHardwareBreakpoint(i, t, addr); err != nil {
return nil, fmt.Errorf("could not set hardware breakpoint on thread %d: %s", t, err)
}
}
dbp.HWBreakPoints[i] = dbp.newHardwareBreakpoint(fn.Name, f, l, addr, nil, temp, i)
return dbp.HWBreakPoints[i], nil
......
......@@ -46,11 +46,6 @@ func setHardwareBreakpoint(reg, tid int, addr uint64) error {
return PtracePokeUser(tid, dr7off, dr7)
}
// Error out if dr`reg` is already used
if dr7&(0x3<<uint(reg*C.DR_ENABLE_SIZE)) != 0 {
return fmt.Errorf("dr%d already enabled", reg)
}
// Set the debug register `reg` with the address of the
// instruction we want to trigger a debug exception.
if err := PtracePokeUser(tid, drxoff, uintptr(addr)); err != nil {
......
......@@ -263,27 +263,27 @@ func (dbp *DebuggedProcess) next() error {
var goroutineExiting bool
var waitCount int
for _, th := range dbp.Threads {
if th.blocked() { // Continue threads that aren't running go code.
if err = th.Continue(); err != nil {
return err
}
if th.blocked() {
// Ignore threads that aren't running go code.
continue
}
waitCount++
if err = th.Next(); err != nil {
if err = th.SetNextBreakpoints(); err != nil {
if err, ok := err.(GoroutineExitingError); ok {
waitCount = waitCount - 1 + chanRecvCount
if err.goid == g.Id {
goroutineExiting = true
}
if err := th.Continue(); err != nil {
return err
}
continue
}
return err
}
}
for _, th := range dbp.Threads {
if err = th.Continue(); err != nil {
return err
}
}
for waitCount > 0 {
thread, err := dbp.trapWait(-1)
......
......@@ -252,6 +252,14 @@ func (dbp *DebuggedProcess) trapWait(pid int) (*ThreadContext, error) {
if err != nil {
return nil, err
}
for reg, bp := range dbp.HWBreakPoints {
if bp == nil {
continue
}
if err = setHardwareBreakpoint(reg, th.Id, bp.Addr); err != nil {
return nil, err
}
}
if err = th.Continue(); err != nil {
return nil, fmt.Errorf("could not continue new thread %d %s", cloned, err)
}
......
......@@ -117,7 +117,7 @@ func (thread *ThreadContext) Location() (*Location, error) {
// This functionality is implemented by finding all possible next lines
// and setting a breakpoint at them. Once we've set a breakpoint at each
// potential line, we continue the thread.
func (thread *ThreadContext) Next() (err error) {
func (thread *ThreadContext) SetNextBreakpoints() (err error) {
curpc, err := thread.PC()
if err != nil {
return err
......@@ -144,7 +144,7 @@ func (thread *ThreadContext) Next() (err error) {
return err
}
}
return thread.Continue()
return nil
}
// Go routine is exiting.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册