Skip to content

Commit e61f18d

Browse files
committed
Address PR issues
1 parent 602fe95 commit e61f18d

6 files changed

Lines changed: 354 additions & 18 deletions

File tree

src/MIDebugEngine/AD7.Impl/AD7BoundBreakpoint.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.VisualStudio.Debugger.Interop;
66
using System;
77
using System.Diagnostics;
8+
using System.Threading.Tasks;
89

910
namespace Microsoft.MIDebugEngine
1011
{
@@ -162,15 +163,18 @@ int IDebugBoundBreakpoint2.SetCondition(BP_CONDITION bpCondition)
162163
int IDebugBoundBreakpoint2.SetHitCount(uint dwHitCount)
163164
{
164165
_bp.SetHitCount(dwHitCount);
166+
_pendingBreakpoint?.RecomputeBreakAfter(dwHitCount);
167+
165168
return Constants.S_OK;
166169
}
167170

168171
/// <summary>
169-
/// Syncs the hit count from GDB's "times" field in =breakpoint-modified events.
172+
/// Syncs the hit count from GDB's "times" field using a delta
173+
/// to preserve any user-initiated hit count reset.
170174
/// </summary>
171175
internal void SetHitCount(uint hitCount)
172176
{
173-
_bp.SetHitCount(hitCount);
177+
_bp.SetGdbHitCount(hitCount);
174178
}
175179

176180
// This is used to specify the breakpoint hit count condition.
@@ -183,6 +187,8 @@ int IDebugBoundBreakpoint2.SetPassCount(BP_PASSCOUNT bpPassCount)
183187

184188
#endregion
185189

190+
internal uint HitCount => _bp.HitCount;
191+
186192
internal void IncrementHitCount()
187193
{
188194
_bp.IncrementHitCount();
@@ -211,6 +217,33 @@ internal bool ShouldBreak()
211217
}
212218
}
213219

220+
/// <summary>
221+
/// Re-sends -break-after to GDB after a pass count breakpoint fires.
222+
/// MOD: skips passCount-1 hits. EQUAL: clears the ignore count.
223+
/// </summary>
224+
internal async Task RearmBreakAfterAsync()
225+
{
226+
uint ignoreCount;
227+
switch (_passCountStyle)
228+
{
229+
case enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_MOD:
230+
if (_passCountValue == 0) return;
231+
ignoreCount = _passCountValue - 1;
232+
break;
233+
case enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_EQUAL:
234+
ignoreCount = 0;
235+
break;
236+
default:
237+
return;
238+
}
239+
240+
PendingBreakpoint bp = _pendingBreakpoint?.PendingBreakpoint;
241+
if (bp != null && _engine?.DebuggedProcess != null)
242+
{
243+
await bp.SetBreakAfterAsync(ignoreCount, _engine.DebuggedProcess);
244+
}
245+
}
246+
214247
internal void UpdateAddr(ulong addr)
215248
{
216249
_bp.Addr = addr;

src/MIDebugEngine/AD7.Impl/AD7PendingBreakpoint.cs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -697,23 +697,27 @@ int IDebugPendingBreakpoint2.SetPassCount(BP_PASSCOUNT bpPassCount)
697697
}
698698
}
699699

700-
// Re-send -break-after to GDB with the updated ignore count, accounting
701-
// for the current hit count so the breakpoint fires at the right time.
702-
if (bp != null && bpPassCount.stylePassCount != enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_NONE)
700+
// When the pass count is cleared (NONE), send ignore count 0 to clear
701+
// any stale GDB ignore count from the previous condition.
702+
if (bp != null)
703703
{
704-
uint currentHits = 0;
705-
lock (_boundBreakpoints)
704+
uint ignoreCount = 0;
705+
if (bpPassCount.stylePassCount != enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_NONE)
706706
{
707-
foreach (AD7BoundBreakpoint boundBp in _boundBreakpoints)
707+
uint currentHits = 0;
708+
lock (_boundBreakpoints)
708709
{
709-
uint hc;
710-
if (((IDebugBoundBreakpoint2)boundBp).GetHitCount(out hc) == Constants.S_OK && hc > currentHits)
710+
foreach (AD7BoundBreakpoint boundBp in _boundBreakpoints)
711711
{
712-
currentHits = hc;
712+
uint hc;
713+
if (((IDebugBoundBreakpoint2)boundBp).GetHitCount(out hc) == Constants.S_OK && hc > currentHits)
714+
{
715+
currentHits = hc;
716+
}
713717
}
714718
}
719+
ignoreCount = ComputeIgnoreCount(bpPassCount.stylePassCount, bpPassCount.dwPassCount, currentHits);
715720
}
716-
uint ignoreCount = ComputeIgnoreCount(bpPassCount.stylePassCount, bpPassCount.dwPassCount, currentHits);
717721
_engine.DebuggedProcess.WorkerThread.RunOperation(() =>
718722
{
719723
_engine.DebuggedProcess.AddInternalBreakAction(
@@ -724,6 +728,28 @@ int IDebugPendingBreakpoint2.SetPassCount(BP_PASSCOUNT bpPassCount)
724728
return Constants.S_OK;
725729
}
726730

731+
/// <summary>
732+
/// Re-sends -break-after to GDB after a hit count reset.
733+
/// </summary>
734+
internal void RecomputeBreakAfter(uint currentHits)
735+
{
736+
if (_bp == null
737+
|| (_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_PASSCOUNT) == 0
738+
|| _bpRequestInfo.bpPassCount.stylePassCount == enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_NONE)
739+
{
740+
return;
741+
}
742+
743+
PendingBreakpoint bp = _bp;
744+
uint ignoreCount = ComputeIgnoreCount(_bpRequestInfo.bpPassCount.stylePassCount, _bpRequestInfo.bpPassCount.dwPassCount, currentHits);
745+
_engine.DebuggedProcess.WorkerThread.RunOperation(() =>
746+
{
747+
_engine.DebuggedProcess.AddInternalBreakAction(
748+
() => bp.SetBreakAfterAsync(ignoreCount, _engine.DebuggedProcess)
749+
);
750+
});
751+
}
752+
727753
// Toggles the virtualized state of this pending breakpoint. When a pending breakpoint is virtualized,
728754
// the debug engine will attempt to bind it every time new code loads into the program.
729755
// The sample engine will does not support this.

src/MIDebugEngine/Engine.Impl/BreakpointManager.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,16 @@ public async Task BreakpointModified(object sender, EventArgs args)
8080
{
8181
if (boundBp.HasPassCount)
8282
{
83+
uint previousHitCount = boundBp.HitCount;
8384
boundBp.SetHitCount(times);
85+
86+
// Re-arm GDB's ignore count so it skips to the next target hit.
87+
// Guard on hit count change to avoid looping: -break-after
88+
// itself triggers =breakpoint-modified.
89+
if (boundBp.HitCount != previousHitCount)
90+
{
91+
await boundBp.RearmBreakAfterAsync();
92+
}
8493
}
8594
}
8695
}

src/MIDebugEngine/Engine.Impl/Breakpoints.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ internal class BoundBreakpoint
375375
/*OPTIONAL*/
376376
public string FunctionName { get; private set; }
377377
internal uint HitCount { get; private set; }
378+
private uint _rawGdbHitCount;
379+
private readonly object _hitCountLock = new object();
378380
internal bool Enabled { get; set; }
379381
internal bool IsDataBreakpoint { get { return _parent.AD7breakpoint.IsDataBreakpoint; } }
380382
private MITextPosition _textPosition;
@@ -450,12 +452,34 @@ internal uint Line
450452

451453
internal void IncrementHitCount()
452454
{
453-
HitCount++;
455+
lock (_hitCountLock)
456+
{
457+
HitCount++;
458+
}
454459
}
455460

456461
internal void SetHitCount(uint count)
457462
{
458-
HitCount = count;
463+
lock (_hitCountLock)
464+
{
465+
HitCount = count;
466+
}
467+
}
468+
469+
/// <summary>
470+
/// Applies the delta from GDB's "times" field, preserving user-initiated resets.
471+
/// </summary>
472+
internal void SetGdbHitCount(uint gdbTimes)
473+
{
474+
lock (_hitCountLock)
475+
{
476+
if (gdbTimes >= _rawGdbHitCount)
477+
{
478+
uint delta = gdbTimes - _rawGdbHitCount;
479+
HitCount += delta;
480+
}
481+
_rawGdbHitCount = gdbTimes;
482+
}
459483
}
460484
}
461485
}

src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,6 @@ public bool SetLogMessage(string logMessage)
197197

198198
#region Hit Conditions
199199

200-
/// <summary>
201-
/// Attempts to parse the hit condition string into a pass count style and value.
202-
/// Returns true if HitCondition is null/empty (no condition) or if it is a valid hit condition.
203-
/// </summary>
204200
/// <summary>
205201
/// Updates the hit condition string so that subsequent <see cref="TryParseHitCondition"/>
206202
/// calls return the new pass count, and future comparisons see the updated value.
@@ -210,6 +206,10 @@ internal void UpdateHitCondition(string hitCondition)
210206
HitCondition = hitCondition;
211207
}
212208

209+
/// <summary>
210+
/// Attempts to parse the hit condition string into a pass count style and value.
211+
/// Returns true if HitCondition is null/empty (no condition) or if it is a valid hit condition.
212+
/// </summary>
213213
internal bool TryParseHitCondition(out enum_BP_PASSCOUNT_STYLE style, out uint passCount)
214214
{
215215
style = enum_BP_PASSCOUNT_STYLE.BP_PASSCOUNT_NONE;

0 commit comments

Comments
 (0)