@@ -47,7 +47,6 @@ type Breakpoint struct {
47
47
48
48
Addr uint64 // Address breakpoint is set for.
49
49
OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction.
50
- Name string // User defined name of the breakpoint
51
50
52
51
WatchExpr string
53
52
WatchType WatchType
@@ -59,14 +58,7 @@ type Breakpoint struct {
59
58
Breaklets []* Breaklet
60
59
61
60
// Breakpoint information
62
- Tracepoint bool // Tracepoint flag
63
- TraceReturn bool
64
- Goroutine bool // Retrieve goroutine information
65
- Stacktrace int // Number of stack frames to retrieve
66
- Variables []string // Variables to evaluate
67
- LoadArgs * LoadConfig
68
- LoadLocals * LoadConfig
69
- UserData interface {} // Any additional information about the breakpoint
61
+ Logical * LogicalBreakpoint
70
62
71
63
// ReturnInfo describes how to collect return variables when this
72
64
// breakpoint is hit as a return breakpoint.
@@ -85,9 +77,6 @@ type Breaklet struct {
85
77
// Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
86
78
Cond ast.Expr
87
79
88
- HitCount map [int ]uint64 // Number of times a breakpoint has been reached in a certain goroutine
89
- TotalHitCount uint64 // Number of times a breakpoint has been reached
90
-
91
80
// DeferReturns: when kind == NextDeferBreakpoint this breakpoint
92
81
// will also check if the caller is runtime.gopanic or if the return
93
82
// address is in the DeferReturns array.
@@ -99,13 +88,6 @@ type Breaklet struct {
99
88
// the function, not when the function is called directly
100
89
DeferReturns []uint64
101
90
102
- // HitCond: if not nil the breakpoint will be triggered only if the evaluated HitCond returns
103
- // true with the TotalHitCount.
104
- HitCond * struct {
105
- Op token.Token
106
- Val int
107
- }
108
-
109
91
// checkPanicCall checks that the breakpoint happened while the function was
110
92
// called by a panic. It is only checked for WatchOutOfScopeBreakpoint Kind.
111
93
checkPanicCall bool
@@ -206,10 +188,12 @@ func (bp *Breakpoint) VerboseDescr() []string {
206
188
r = append (r , fmt .Sprintf ("HWBreakIndex=%#x watchStackOff=%#x" , bp .HWBreakIndex , bp .watchStackOff ))
207
189
}
208
190
191
+ lbp := bp .Logical
192
+
209
193
for _ , breaklet := range bp .Breaklets {
210
194
switch breaklet .Kind {
211
195
case UserBreakpoint :
212
- r = append (r , fmt .Sprintf ("User Cond=%q HitCond=%v" , exprToString (breaklet .Cond ), breaklet .HitCond ))
196
+ r = append (r , fmt .Sprintf ("User Cond=%q HitCond=%v" , exprToString (breaklet .Cond ), lbp .HitCond ))
213
197
case NextBreakpoint :
214
198
r = append (r , fmt .Sprintf ("Next Cond=%q" , exprToString (breaklet .Cond )))
215
199
case NextDeferBreakpoint :
@@ -280,11 +264,14 @@ func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, threa
280
264
281
265
switch breaklet .Kind {
282
266
case UserBreakpoint :
283
- if g , err := GetG (thread ); err == nil {
284
- breaklet .HitCount [g .ID ]++
267
+ lbp := bpstate .Breakpoint .Logical
268
+ if lbp != nil {
269
+ if g , err := GetG (thread ); err == nil {
270
+ lbp .HitCount [g .ID ]++
271
+ }
272
+ lbp .TotalHitCount ++
285
273
}
286
- breaklet .TotalHitCount ++
287
- active = checkHitCond (breaklet )
274
+ active = checkHitCond (lbp )
288
275
289
276
case StepBreakpoint , NextBreakpoint , NextDeferBreakpoint :
290
277
nextDeferOk := true
@@ -331,26 +318,26 @@ func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, threa
331
318
}
332
319
333
320
// checkHitCond evaluates bp's hit condition on thread.
334
- func checkHitCond (breaklet * Breaklet ) bool {
335
- if breaklet .HitCond == nil {
321
+ func checkHitCond (lbp * LogicalBreakpoint ) bool {
322
+ if lbp == nil || lbp .HitCond == nil {
336
323
return true
337
324
}
338
325
// Evaluate the breakpoint condition.
339
- switch breaklet .HitCond .Op {
326
+ switch lbp .HitCond .Op {
340
327
case token .EQL :
341
- return int (breaklet .TotalHitCount ) == breaklet .HitCond .Val
328
+ return int (lbp .TotalHitCount ) == lbp .HitCond .Val
342
329
case token .NEQ :
343
- return int (breaklet .TotalHitCount ) != breaklet .HitCond .Val
330
+ return int (lbp .TotalHitCount ) != lbp .HitCond .Val
344
331
case token .GTR :
345
- return int (breaklet .TotalHitCount ) > breaklet .HitCond .Val
332
+ return int (lbp .TotalHitCount ) > lbp .HitCond .Val
346
333
case token .LSS :
347
- return int (breaklet .TotalHitCount ) < breaklet .HitCond .Val
334
+ return int (lbp .TotalHitCount ) < lbp .HitCond .Val
348
335
case token .GEQ :
349
- return int (breaklet .TotalHitCount ) >= breaklet .HitCond .Val
336
+ return int (lbp .TotalHitCount ) >= lbp .HitCond .Val
350
337
case token .LEQ :
351
- return int (breaklet .TotalHitCount ) <= breaklet .HitCond .Val
338
+ return int (lbp .TotalHitCount ) <= lbp .HitCond .Val
352
339
case token .REM :
353
- return int (breaklet .TotalHitCount )% breaklet .HitCond .Val == 0
340
+ return int (lbp .TotalHitCount )% lbp .HitCond .Val == 0
354
341
}
355
342
return false
356
343
}
@@ -468,6 +455,9 @@ func (nbp NoBreakpointError) Error() string {
468
455
type BreakpointMap struct {
469
456
M map [uint64 ]* Breakpoint
470
457
458
+ // Logical is a map of logical breakpoints.
459
+ Logical map [int ]* LogicalBreakpoint
460
+
471
461
// WatchOutOfScope is the list of watchpoints that went out of scope during
472
462
// the last resume operation
473
463
WatchOutOfScope []* Breakpoint
@@ -651,23 +641,42 @@ func (t *Target) setBreakpointInternal(logicalID int, addr uint64, kind Breakpoi
651
641
bpmap := t .Breakpoints ()
652
642
newBreaklet := & Breaklet {Kind : kind , Cond : cond }
653
643
if kind == UserBreakpoint {
654
- newBreaklet .HitCount = map [int ]uint64 {}
655
644
newBreaklet .LogicalID = logicalID
656
645
}
646
+
647
+ setLogicalBreakpoint := func (bp * Breakpoint ) {
648
+ if kind != UserBreakpoint || bp .Logical != nil {
649
+ return
650
+ }
651
+ if bpmap .Logical == nil {
652
+ bpmap .Logical = make (map [int ]* LogicalBreakpoint )
653
+ }
654
+ lbp := bpmap .Logical [logicalID ]
655
+ if lbp == nil {
656
+ lbp = & LogicalBreakpoint {LogicalID : logicalID }
657
+ lbp .HitCount = make (map [int ]uint64 )
658
+ lbp .Enabled = true
659
+ bpmap .Logical [logicalID ] = lbp
660
+ }
661
+ bp .Logical = lbp
662
+ breaklet := bp .UserBreaklet ()
663
+ if breaklet != nil && breaklet .Cond == nil {
664
+ breaklet .Cond = lbp .Cond
665
+ }
666
+ lbp .File = bp .File
667
+ lbp .Line = bp .Line
668
+ fn := t .BinInfo ().PCToFunc (bp .Addr )
669
+ if fn != nil {
670
+ lbp .FunctionName = fn .NameWithoutTypeParams ()
671
+ }
672
+ }
673
+
657
674
if bp , ok := bpmap .M [addr ]; ok {
658
675
if ! bp .canOverlap (kind ) {
659
676
return bp , BreakpointExistsError {bp .File , bp .Line , bp .Addr }
660
677
}
661
- if kind == UserBreakpoint {
662
- bp .Tracepoint = false
663
- bp .TraceReturn = false
664
- bp .Goroutine = false
665
- bp .Stacktrace = 0
666
- bp .Variables = nil
667
- bp .LoadArgs = nil
668
- bp .LoadLocals = nil
669
- }
670
678
bp .Breaklets = append (bp .Breaklets , newBreaklet )
679
+ setLogicalBreakpoint (bp )
671
680
return bp , nil
672
681
}
673
682
@@ -708,6 +717,7 @@ func (t *Target) setBreakpointInternal(logicalID int, addr uint64, kind Breakpoi
708
717
}
709
718
710
719
newBreakpoint .Breaklets = append (newBreakpoint .Breaklets , newBreaklet )
720
+ setLogicalBreakpoint (newBreakpoint )
711
721
712
722
bpmap .M [addr ] = newBreakpoint
713
723
@@ -741,6 +751,9 @@ func (t *Target) ClearBreakpoint(addr uint64) error {
741
751
for i := range bp .Breaklets {
742
752
if bp .Breaklets [i ].Kind == UserBreakpoint {
743
753
bp .Breaklets [i ] = nil
754
+ if bp .WatchExpr == "" {
755
+ bp .Logical = nil
756
+ }
744
757
}
745
758
}
746
759
@@ -805,6 +818,9 @@ func (t *Target) finishClearBreakpoint(bp *Breakpoint) (bool, error) {
805
818
}
806
819
807
820
delete (t .Breakpoints ().M , bp .Addr )
821
+ if bp .WatchExpr != "" && bp .Logical != nil {
822
+ delete (t .Breakpoints ().Logical , bp .Logical .LogicalID )
823
+ }
808
824
return true , nil
809
825
}
810
826
@@ -925,3 +941,36 @@ func returnInfoError(descr string, err error, mem MemoryReadWriter) []*Variable
925
941
v .Name = "return value read error"
926
942
return []* Variable {v }
927
943
}
944
+
945
+ // LogicalBreakpoint represents a breakpoint set by a user.
946
+ type LogicalBreakpoint struct {
947
+ LogicalID int
948
+ Name string
949
+ FunctionName string
950
+ File string
951
+ Line int
952
+ Enabled bool
953
+
954
+ Tracepoint bool // Tracepoint flag
955
+ TraceReturn bool
956
+ Goroutine bool // Retrieve goroutine information
957
+ Stacktrace int // Number of stack frames to retrieve
958
+ Variables []string // Variables to evaluate
959
+ LoadArgs * LoadConfig
960
+ LoadLocals * LoadConfig
961
+
962
+ HitCount map [int ]uint64 // Number of times a breakpoint has been reached in a certain goroutine
963
+ TotalHitCount uint64 // Number of times a breakpoint has been reached
964
+
965
+ // HitCond: if not nil the breakpoint will be triggered only if the evaluated HitCond returns
966
+ // true with the TotalHitCount.
967
+ HitCond * struct {
968
+ Op token.Token
969
+ Val int
970
+ }
971
+
972
+ // Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
973
+ Cond ast.Expr
974
+
975
+ UserData interface {} // Any additional information about the breakpoint
976
+ }
0 commit comments