diff --git a/_fixtures/panic.go b/_fixtures/panic.go new file mode 100644 index 00000000..63729026 --- /dev/null +++ b/_fixtures/panic.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("BOOM!") +} diff --git a/proc/proc.go b/proc/proc.go index 6bb00dea..5f1d3d0e 100644 --- a/proc/proc.go +++ b/proc/proc.go @@ -741,6 +741,16 @@ func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, e // the offset of g struct inside TLS dbp.SelectedGoroutine, _ = dbp.CurrentThread.GetG() + panicpc, err := dbp.FindFunctionLocation("runtime.startpanic", true, 0) + if err == nil { + bp, err := dbp.SetBreakpoint(panicpc) + if err == nil { + bp.Name = "unrecovered-panic" + bp.ID = -1 + dbp.breakpointIDCounter-- + } + } + return dbp, nil } diff --git a/proc/proc_test.go b/proc/proc_test.go index a12b58ae..a3b046f7 100644 --- a/proc/proc_test.go +++ b/proc/proc_test.go @@ -269,7 +269,7 @@ func TestClearBreakpointBreakpoint(t *testing.T) { t.Fatalf("Breakpoint was not cleared data: %#v, int3: %#v", data, int3) } - if len(p.Breakpoints) != 0 { + if countBreakpoints(p) != 0 { t.Fatal("Breakpoint not removed internally") } }) @@ -279,6 +279,16 @@ type nextTest struct { begin, end int } +func countBreakpoints(p *Process) int { + bpcount := 0 + for _, bp := range p.Breakpoints { + if bp.ID >= 0 { + bpcount++ + } + } + return bpcount +} + func testnext(program string, testcases []nextTest, initialLocation string, t *testing.T) { withTestProcess(program, t, func(p *Process, fixture protest.Fixture) { bp, err := setFunctionBreakpoint(p, initialLocation) @@ -301,7 +311,7 @@ func testnext(program string, testcases []nextTest, initialLocation string, t *t } } - if len(p.Breakpoints) != 0 { + if countBreakpoints(p) != 0 { t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints)) } }) @@ -1635,3 +1645,13 @@ func TestIssue149(t *testing.T) { assertNoError(err, t, "FindFileLocation()") }) } + +func TestPanicBreakpoint(t *testing.T) { + withTestProcess("panic", t, func(p *Process, fixture protest.Fixture) { + assertNoError(p.Continue(), t, "Continue()") + bp := p.CurrentBreakpoint() + if bp == nil || bp.Name != "unrecovered-panic" { + t.Fatalf("not on unrecovered-panic breakpoint: %v", p.CurrentBreakpoint) + } + }) +} diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 8e441e73..6b2b4fd5 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -114,6 +114,9 @@ func (d *Debugger) Restart() error { return fmt.Errorf("could not launch process: %s", err) } for _, oldBp := range d.breakpoints() { + if oldBp.ID < 0 { + continue + } newBp, err := p.SetBreakpoint(oldBp.Addr) if err != nil { return err diff --git a/service/test/integration_test.go b/service/test/integration_test.go index 71226aad..fdeb45d7 100644 --- a/service/test/integration_test.go +++ b/service/test/integration_test.go @@ -358,6 +358,18 @@ func TestClientServer_breakAtNonexistentPoint(t *testing.T) { }) } +func countBreakpoints(t *testing.T, c service.Client) int { + bps, err := c.ListBreakpoints() + assertNoError(err, t, "ListBreakpoints()") + bpcount := 0 + for _, bp := range bps { + if bp.ID >= 0 { + bpcount++ + } + } + return bpcount +} + func TestClientServer_clearBreakpoint(t *testing.T) { withTestClient("testprog", t, func(c service.Client) { bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sleepytime", Line: 1}) @@ -365,8 +377,7 @@ func TestClientServer_clearBreakpoint(t *testing.T) { t.Fatalf("Unexpected error: %v", err) } - bps, err := c.ListBreakpoints() - if e, a := 1, len(bps); e != a { + if e, a := 1, countBreakpoints(t, c); e != a { t.Fatalf("Expected breakpoint count %d, got %d", e, a) } @@ -379,8 +390,7 @@ func TestClientServer_clearBreakpoint(t *testing.T) { t.Fatalf("Expected deleted breakpoint ID %v, got %v", bp.ID, deleted.ID) } - bps, err = c.ListBreakpoints() - if e, a := 0, len(bps); e != a { + if e, a := 0, countBreakpoints(t, c); e != a { t.Fatalf("Expected breakpoint count %d, got %d", e, a) } }) diff --git a/terminal/command.go b/terminal/command.go index cb2afe60..e0499311 100644 --- a/terminal/command.go +++ b/terminal/command.go @@ -515,6 +515,10 @@ func clearAll(t *Term, ctx callContext, args string) error { } } + if bp.ID < 0 { + continue + } + _, err := t.client.ClearBreakpoint(bp.ID) if err != nil { fmt.Printf("Couldn't delete %s at %s: %s\n", formatBreakpointName(bp, false), formatBreakpointLocation(bp), err)