diff --git a/proctl/proctl_linux_amd64.go b/proctl/proctl_linux_amd64.go index 373e9022..c41abe0a 100644 --- a/proctl/proctl_linux_amd64.go +++ b/proctl/proctl_linux_amd64.go @@ -131,6 +131,23 @@ func (dbp *DebuggedProcess) Break(fname string) (*BreakPoint, error) { return breakpoint, nil } +// Clears a breakpoint. +func (dbp *DebuggedProcess) Clear(fname string) error { + bp, ok := dbp.BreakPoints[fname] + if !ok { + return fmt.Errorf("No breakpoint currently set for %s", fname) + } + + err := dbp.restoreInstruction(bp.Addr, bp.OriginalData) + if err != nil { + return err + } + + dbp.BreakPoints[fname] = nil + + return nil +} + // Steps through process. func (dbp *DebuggedProcess) Step() error { regs, err := dbp.Registers() diff --git a/proctl/proctl_test.go b/proctl/proctl_test.go index f7f2524b..26d724d0 100644 --- a/proctl/proctl_test.go +++ b/proctl/proctl_test.go @@ -1,11 +1,22 @@ package proctl import ( + "bytes" "os/exec" "syscall" "testing" ) +func dataAtAddr(pid int, addr uint64) ([]byte, error) { + data := make([]byte, 1) + _, err := syscall.PtracePeekData(pid, uintptr(addr), data) + if err != nil { + return nil, err + } + + return data, nil +} + func StartTestProcess(name string) (*exec.Cmd, error) { cmd := exec.Command("../fixtures/" + name) @@ -168,3 +179,40 @@ func TestBreakPointWithNonExistantFunction(t *testing.T) { t.Fatal("Should not be able to break at non existant function") } } + +func TestClearBreakPoint(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) + } + + bp, err := p.Break("main.sleepytime") + if err != nil { + t.Fatal("Break():", err) + } + + int3, err := dataAtAddr(pid, bp.Addr) + if err != nil { + t.Fatal(err) + } + + err = p.Clear("main.sleepytime") + if err != nil { + t.Fatal("Break():", err) + } + + data, err := dataAtAddr(pid, bp.Addr) + if err != nil { + t.Fatal(err) + } + + if bytes.Equal(data, int3) { + t.Fatalf("Breakpoint was not cleared data: %#v, int3: %#v", data, int3) + } +}