mirror of
https://github.com/go-delve/delve.git
synced 2025-10-27 20:23:41 +08:00
proc: do not assign temporary breakpoint IDs (#2650)
Internal breakpoints do not need IDs and assigning them from a counter separate from the user ID counter can be a cause of confusion. If a user breakpoint is overlayed on top of a pre-existing internal breakpoint the temporary ID will be surfaced as if it was a user ID, possibly conflicting with another user ID. If a temporary breakpoint is overlayed on top of a pre-existing user breakpoint and the user breakpoint is first deleted and then re-created, the user ID will be resurrected along with the breakpoint, instead of allocating a fresh one. This change removes internal breakpoint IDs entirely, only user breakpoints receive an ID.
This commit is contained in:
committed by
GitHub
parent
b8f8cd82a6
commit
a97da22762
@ -27,6 +27,8 @@ const (
|
||||
|
||||
unrecoveredPanicID = -1
|
||||
fatalThrowID = -2
|
||||
|
||||
NoLogicalID = -1000 // Logical breakpoint ID for breakpoints internal breakpoints.
|
||||
)
|
||||
|
||||
// Breakpoint represents a physical breakpoint. Stores information on the break
|
||||
@ -41,7 +43,6 @@ type Breakpoint struct {
|
||||
Addr uint64 // Address breakpoint is set for.
|
||||
OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction.
|
||||
Name string // User defined name of the breakpoint
|
||||
LogicalID int // ID of the logical breakpoint that owns this physical breakpoint
|
||||
|
||||
WatchExpr string
|
||||
WatchType WatchType
|
||||
@ -74,6 +75,8 @@ type Breaklet struct {
|
||||
// stepping).
|
||||
Kind BreakpointKind
|
||||
|
||||
LogicalID int // ID of the logical breakpoint that owns this physical breakpoint
|
||||
|
||||
// Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
|
||||
Cond ast.Expr
|
||||
|
||||
@ -175,7 +178,16 @@ func (wtype WatchType) withSize(sz uint8) WatchType {
|
||||
var ErrHWBreakUnsupported = errors.New("hardware breakpoints not implemented")
|
||||
|
||||
func (bp *Breakpoint) String() string {
|
||||
return fmt.Sprintf("Breakpoint %d at %#v %s:%d", bp.LogicalID, bp.Addr, bp.File, bp.Line)
|
||||
return fmt.Sprintf("Breakpoint %d at %#v %s:%d", bp.LogicalID(), bp.Addr, bp.File, bp.Line)
|
||||
}
|
||||
|
||||
func (bp *Breakpoint) LogicalID() int {
|
||||
for _, breaklet := range bp.Breaklets {
|
||||
if breaklet.Kind == UserBreakpoint {
|
||||
return breaklet.LogicalID
|
||||
}
|
||||
}
|
||||
return NoLogicalID
|
||||
}
|
||||
|
||||
// VerboseDescr returns a string describing parts of the breakpoint struct
|
||||
@ -448,8 +460,7 @@ type BreakpointMap struct {
|
||||
// the last resume operation
|
||||
WatchOutOfScope []*Breakpoint
|
||||
|
||||
breakpointIDCounter int
|
||||
internalBreakpointIDCounter int
|
||||
breakpointIDCounter int
|
||||
}
|
||||
|
||||
// NewBreakpointMap creates a new BreakpointMap.
|
||||
@ -610,11 +621,22 @@ func (t *Target) setBreakpointInternal(addr uint64, kind BreakpointKind, wtype W
|
||||
newBreaklet := &Breaklet{Kind: kind, Cond: cond}
|
||||
if kind == UserBreakpoint {
|
||||
newBreaklet.HitCount = map[int]uint64{}
|
||||
bpmap.breakpointIDCounter++
|
||||
newBreaklet.LogicalID = bpmap.breakpointIDCounter
|
||||
}
|
||||
if bp, ok := bpmap.M[addr]; ok {
|
||||
if !bp.canOverlap(kind) {
|
||||
return bp, BreakpointExistsError{bp.File, bp.Line, bp.Addr}
|
||||
}
|
||||
if kind == UserBreakpoint {
|
||||
bp.Tracepoint = false
|
||||
bp.TraceReturn = false
|
||||
bp.Goroutine = false
|
||||
bp.Stacktrace = 0
|
||||
bp.Variables = nil
|
||||
bp.LoadArgs = nil
|
||||
bp.LoadLocals = nil
|
||||
}
|
||||
bp.Breaklets = append(bp.Breaklets, newBreaklet)
|
||||
return bp, nil
|
||||
}
|
||||
@ -655,14 +677,6 @@ func (t *Target) setBreakpointInternal(addr uint64, kind BreakpointKind, wtype W
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if kind != UserBreakpoint {
|
||||
bpmap.internalBreakpointIDCounter++
|
||||
newBreakpoint.LogicalID = bpmap.internalBreakpointIDCounter
|
||||
} else {
|
||||
bpmap.breakpointIDCounter++
|
||||
newBreakpoint.LogicalID = bpmap.breakpointIDCounter
|
||||
}
|
||||
|
||||
newBreakpoint.Breaklets = append(newBreakpoint.Breaklets, newBreaklet)
|
||||
|
||||
bpmap.M[addr] = newBreakpoint
|
||||
@ -675,8 +689,13 @@ func (t *Target) SetBreakpointWithID(id int, addr uint64) (*Breakpoint, error) {
|
||||
bpmap := t.Breakpoints()
|
||||
bp, err := t.SetBreakpoint(addr, UserBreakpoint, nil)
|
||||
if err == nil {
|
||||
bp.LogicalID = id
|
||||
bpmap.breakpointIDCounter--
|
||||
for _, breaklet := range bp.Breaklets {
|
||||
if breaklet.Kind == UserBreakpoint {
|
||||
breaklet.LogicalID = id
|
||||
bpmap.breakpointIDCounter--
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return bp, err
|
||||
}
|
||||
@ -693,13 +712,13 @@ func (bp *Breakpoint) canOverlap(kind BreakpointKind) bool {
|
||||
}
|
||||
|
||||
// ClearBreakpoint clears the breakpoint at addr.
|
||||
func (t *Target) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
|
||||
func (t *Target) ClearBreakpoint(addr uint64) error {
|
||||
if valid, err := t.Valid(); !valid {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
bp, ok := t.Breakpoints().M[addr]
|
||||
if !ok {
|
||||
return nil, NoBreakpointError{Addr: addr}
|
||||
return NoBreakpointError{Addr: addr}
|
||||
}
|
||||
|
||||
for i := range bp.Breaklets {
|
||||
@ -710,18 +729,18 @@ func (t *Target) ClearBreakpoint(addr uint64) (*Breakpoint, error) {
|
||||
|
||||
_, err := t.finishClearBreakpoint(bp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if bp.WatchExpr != "" && bp.watchStackOff != 0 {
|
||||
// stack watchpoint, must remove all its WatchOutOfScopeBreakpoints/StackResizeBreakpoints
|
||||
err := t.clearStackWatchBreakpoints(bp)
|
||||
if err != nil {
|
||||
return bp, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return bp, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearSteppingBreakpoints removes all stepping breakpoints from the map,
|
||||
|
||||
Reference in New Issue
Block a user