mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +08:00
service: fix breakpoint IDs after Restart with disabled breakpoints (#2425)
When restarting we must take care of setting breakpoint IDs correctly so that enabled breakpoints do not end up having the same ID as a disabled breakpoint, also we must make sure that breakpoints created after restart will not get an ID already used by a disabled breakpoint.
This commit is contained in:
committed by
GitHub
parent
f3d7b25fdf
commit
781ad72d62
@ -359,3 +359,8 @@ func (t *Target) createFatalThrowBreakpoint() {
|
|||||||
func (t *Target) CurrentThread() Thread {
|
func (t *Target) CurrentThread() Thread {
|
||||||
return t.currentThread
|
return t.currentThread
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNextBreakpointID sets the breakpoint ID of the next breakpoint
|
||||||
|
func (t *Target) SetNextBreakpointID(id int) {
|
||||||
|
t.Breakpoints().breakpointIDCounter = id
|
||||||
|
}
|
||||||
|
|||||||
@ -509,23 +509,27 @@ func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []
|
|||||||
discarded := []api.DiscardedBreakpoint{}
|
discarded := []api.DiscardedBreakpoint{}
|
||||||
breakpoints := api.ConvertBreakpoints(d.breakpoints())
|
breakpoints := api.ConvertBreakpoints(d.breakpoints())
|
||||||
d.target = p
|
d.target = p
|
||||||
|
maxID := 0
|
||||||
for _, oldBp := range breakpoints {
|
for _, oldBp := range breakpoints {
|
||||||
if oldBp.ID < 0 {
|
if oldBp.ID < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if oldBp.ID > maxID {
|
||||||
|
maxID = oldBp.ID
|
||||||
|
}
|
||||||
if len(oldBp.File) > 0 {
|
if len(oldBp.File) > 0 {
|
||||||
addrs, err := proc.FindFileLocation(p, oldBp.File, oldBp.Line)
|
addrs, err := proc.FindFileLocation(p, oldBp.File, oldBp.Line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
discarded = append(discarded, api.DiscardedBreakpoint{Breakpoint: oldBp, Reason: err.Error()})
|
discarded = append(discarded, api.DiscardedBreakpoint{Breakpoint: oldBp, Reason: err.Error()})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
createLogicalBreakpoint(d, addrs, oldBp)
|
createLogicalBreakpoint(d, addrs, oldBp, oldBp.ID)
|
||||||
} else {
|
} else {
|
||||||
// Avoid setting a breakpoint based on address when rebuilding
|
// Avoid setting a breakpoint based on address when rebuilding
|
||||||
if rebuild {
|
if rebuild {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newBp, err := p.SetBreakpoint(oldBp.Addr, proc.UserBreakpoint, nil)
|
newBp, err := p.SetBreakpointWithID(oldBp.ID, oldBp.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -534,6 +538,12 @@ func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, bp := range d.disabledBreakpoints {
|
||||||
|
if bp.ID > maxID {
|
||||||
|
maxID = bp.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.target.SetNextBreakpointID(maxID)
|
||||||
return discarded, nil
|
return discarded, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +662,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
createdBp, err := createLogicalBreakpoint(d, addrs, requestedBp)
|
createdBp, err := createLogicalBreakpoint(d, addrs, requestedBp, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -662,7 +672,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin
|
|||||||
|
|
||||||
// createLogicalBreakpoint creates one physical breakpoint for each address
|
// createLogicalBreakpoint creates one physical breakpoint for each address
|
||||||
// in addrs and associates all of them with the same logical breakpoint.
|
// in addrs and associates all of them with the same logical breakpoint.
|
||||||
func createLogicalBreakpoint(d *Debugger, addrs []uint64, requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
|
func createLogicalBreakpoint(d *Debugger, addrs []uint64, requestedBp *api.Breakpoint, id int) (*api.Breakpoint, error) {
|
||||||
p := d.target
|
p := d.target
|
||||||
|
|
||||||
if dbp, ok := d.disabledBreakpoints[requestedBp.ID]; ok {
|
if dbp, ok := d.disabledBreakpoints[requestedBp.ID]; ok {
|
||||||
@ -672,7 +682,11 @@ func createLogicalBreakpoint(d *Debugger, addrs []uint64, requestedBp *api.Break
|
|||||||
bps := make([]*proc.Breakpoint, len(addrs))
|
bps := make([]*proc.Breakpoint, len(addrs))
|
||||||
var err error
|
var err error
|
||||||
for i := range addrs {
|
for i := range addrs {
|
||||||
|
if id > 0 {
|
||||||
|
bps[i], err = p.SetBreakpointWithID(id, addrs[i])
|
||||||
|
} else {
|
||||||
bps[i], err = p.SetBreakpoint(addrs[i], proc.UserBreakpoint, nil)
|
bps[i], err = p.SetBreakpoint(addrs[i], proc.UserBreakpoint, nil)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -871,7 +885,7 @@ func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint {
|
|||||||
func (d *Debugger) findBreakpoint(id int) []*proc.Breakpoint {
|
func (d *Debugger) findBreakpoint(id int) []*proc.Breakpoint {
|
||||||
var bps []*proc.Breakpoint
|
var bps []*proc.Breakpoint
|
||||||
for _, bp := range d.target.Breakpoints().M {
|
for _, bp := range d.target.Breakpoints().M {
|
||||||
if bp.LogicalID == id {
|
if bp.IsUser() && bp.LogicalID == id {
|
||||||
bps = append(bps, bp)
|
bps = append(bps, bp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2277,3 +2277,34 @@ func TestDetachLeaveRunning(t *testing.T) {
|
|||||||
defer server.Stop()
|
defer server.Stop()
|
||||||
assertNoError(client.Detach(false), t, "Detach")
|
assertNoError(client.Detach(false), t, "Detach")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertNoDuplicateBreakpoints(t *testing.T, c service.Client) {
|
||||||
|
t.Helper()
|
||||||
|
bps, _ := c.ListBreakpoints()
|
||||||
|
seen := make(map[int]bool)
|
||||||
|
for _, bp := range bps {
|
||||||
|
t.Logf("%#v\n", bp)
|
||||||
|
if seen[bp.ID] {
|
||||||
|
t.Fatalf("duplicate breakpoint ID %d", bp.ID)
|
||||||
|
}
|
||||||
|
seen[bp.ID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToggleBreakpointRestart(t *testing.T) {
|
||||||
|
// Checks that breakpoints IDs do not overlap after Restart if there are disabled breakpoints.
|
||||||
|
withTestClient2("testtoggle", t, func(c service.Client) {
|
||||||
|
bp1, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint"})
|
||||||
|
assertNoError(err, t, "CreateBreakpoint 1")
|
||||||
|
_, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 2, Name: "secondbreakpoint"})
|
||||||
|
assertNoError(err, t, "CreateBreakpoint 2")
|
||||||
|
_, err = c.ToggleBreakpoint(bp1.ID)
|
||||||
|
assertNoError(err, t, "ToggleBreakpoint")
|
||||||
|
_, err = c.Restart(false)
|
||||||
|
assertNoError(err, t, "Restart")
|
||||||
|
assertNoDuplicateBreakpoints(t, c)
|
||||||
|
_, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 3, Name: "thirdbreakpoint"})
|
||||||
|
assertNoError(err, t, "CreateBreakpoint 3")
|
||||||
|
assertNoDuplicateBreakpoints(t, c)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user