diff --git a/fixtures/continuetestprog b/fixtures/continuetestprog new file mode 100755 index 00000000..6ddb34a0 Binary files /dev/null and b/fixtures/continuetestprog differ diff --git a/fixtures/continuetestprog.go b/fixtures/continuetestprog.go new file mode 100644 index 00000000..a230c140 --- /dev/null +++ b/fixtures/continuetestprog.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "time" +) + +func sleepytime() { + time.Sleep(time.Millisecond) +} + +func sayhi() { + fmt.Println("Hello, World!") +} + +func main() { + sleepytime() + sayhi() +} diff --git a/fixtures/testprog b/fixtures/testprog index 8eb45e98..96b6ffee 100755 Binary files a/fixtures/testprog and b/fixtures/testprog differ diff --git a/fixtures/testprog.go b/fixtures/testprog.go index 85f98a93..a7accd7c 100644 --- a/fixtures/testprog.go +++ b/fixtures/testprog.go @@ -5,7 +5,17 @@ import ( "time" ) -func main() { +func sleepytime() { time.Sleep(time.Millisecond) +} + +func sayhi() { fmt.Println("Hello, World!") } + +func main() { + for { + sleepytime() + sayhi() + } +} diff --git a/proctl/proctl_linux_amd64.go b/proctl/proctl_linux_amd64.go index 206b84c9..72b914e5 100644 --- a/proctl/proctl_linux_amd64.go +++ b/proctl/proctl_linux_amd64.go @@ -78,6 +78,22 @@ func (dbp *DebuggedProcess) Registers() (*syscall.PtraceRegs, error) { return dbp.Regs, nil } +// Sets a breakpoint in the running process. +func (dbp *DebuggedProcess) Break(fname string) error { + var ( + breakpoint = []byte{'0', 'x', 'C', 'C'} + fn = dbp.GoSymTable.LookupFunc(fname) + addr = uintptr(fn.LineTable.PC) + ) + + _, err := syscall.PtracePokeData(dbp.Pid, addr, breakpoint) + if err != nil { + return err + } + + return nil +} + // Steps through process. func (dbp *DebuggedProcess) Step() error { err := dbp.handleResult(syscall.PtraceSingleStep(dbp.Pid)) diff --git a/proctl/proctl_test.go b/proctl/proctl_test.go index 80751425..c84c8d06 100644 --- a/proctl/proctl_test.go +++ b/proctl/proctl_test.go @@ -6,8 +6,8 @@ import ( "testing" ) -func StartTestProcess() (*exec.Cmd, error) { - cmd := exec.Command("../fixtures/testprog") +func StartTestProcess(name string) (*exec.Cmd, error) { + cmd := exec.Command("../fixtures/" + name) err := cmd.Start() if err != nil { @@ -18,7 +18,7 @@ func StartTestProcess() (*exec.Cmd, error) { } func TestAttachProcess(t *testing.T) { - cmd, err := StartTestProcess() + cmd, err := StartTestProcess("testprog") if err != nil { t.Fatal("Starting test process:", err) } @@ -32,10 +32,12 @@ func TestAttachProcess(t *testing.T) { if !p.ProcessState.Sys().(syscall.WaitStatus).Stopped() { t.Errorf("Process was not stopped correctly") } + + cmd.Process.Kill() } func TestStep(t *testing.T) { - cmd, err := StartTestProcess() + cmd, err := StartTestProcess("testprog") if err != nil { t.Fatal("Starting test process:", err) } @@ -71,7 +73,7 @@ func TestStep(t *testing.T) { } func TestContinue(t *testing.T) { - cmd, err := StartTestProcess() + cmd, err := StartTestProcess("continuetestprog") if err != nil { t.Fatal("Starting test process:", err) } @@ -95,3 +97,41 @@ func TestContinue(t *testing.T) { t.Fatal("Process did not exit successfully") } } + +func TestBreakPoint(t *testing.T) { + cmd, err := StartTestProcess("testprog") + if err != nil { + t.Fatal("Starting test process:", err) + } + + pid := cmd.Process.Pid + p, err := NewDebugProcess(pid) + if err != nil { + t.Fatal("NewDebugProcess():", err) + } + + err = p.Break("main.sleepytime") + if err != nil { + t.Fatal("Break():", err) + } + + sleepytimefunc := p.GoSymTable.LookupFunc("main.sleepytime") + sleepyaddr := sleepytimefunc.LineTable.PC + + err = p.Continue() + if err != nil { + t.Fatal("Continue():", err) + } + + regs, err := p.Registers() + if err != nil { + t.Fatal("Registers():", err) + } + + pc := regs.PC() + if pc != sleepyaddr { + t.Fatal("Break not respected:\nPC:%d\nFN:%d\n", pc, sleepyaddr) + } + + cmd.Process.Kill() +}