mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +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
	 aarzilli
					aarzilli