mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +08:00
proc: Breakpoint to catch unrecovered panics
Automatically sets a breakpoint on runtime.startpanic, the function that gets called by runtime.dopanic when a panic is not recovered. Implements #317
This commit is contained in:
5
_fixtures/panic.go
Normal file
5
_fixtures/panic.go
Normal file
@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
panic("BOOM!")
|
||||
}
|
||||
10
proc/proc.go
10
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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user