Skip to content

Fix x64 data breakpoint handling after CORINFO_HELP_ARRADDR_ST inlining#127251

Merged
tommcdon merged 3 commits intodotnet:mainfrom
tommcdon:dev/tommcdon/fix_data_breakpoints
Apr 23, 2026
Merged

Fix x64 data breakpoint handling after CORINFO_HELP_ARRADDR_ST inlining#127251
tommcdon merged 3 commits intodotnet:mainfrom
tommcdon:dev/tommcdon/fix_data_breakpoints

Conversation

@tommcdon
Copy link
Copy Markdown
Member

After #126547, the WriteBarrier FCall was converted from native (FCall) to managed. This affected the debugger's unwind logic for data breakpoint handling (AdjustContextForJITHelpersForDebugger) resulting in the debugger to unwind into the JIT helper (CastHelpers.StelemRef) rather than user code.

The fix adds a loop after the initial unwind that checks whether the landed-on frame belongs to the CastHelpers
class and continues unwinding until it reaches user code. This only affects x64 data breakpoints, as x86 does a raw single-frame stack pop (restores EIP from ESP) rather than VirtualUnwindToFirstManagedCallFrame, so it was unaffected. ARM64 does not support data breakpoints.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon tommcdon added this to the 11.0.0 milestone Apr 21, 2026
@tommcdon tommcdon requested a review from noahfalk April 21, 2026 22:22
@tommcdon tommcdon self-assigned this Apr 21, 2026
Copilot AI review requested due to automatic review settings April 21, 2026 22:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes x64 data breakpoint unwind behavior after CORINFO_HELP_ARRADDR_ST inlining changed the write barrier call path, so the debugger unwinds back to user code instead of stopping in CastHelpers frames.

Changes:

  • Extends the x64 FEATURE_DATABREAKPOINT unwind logic to keep unwinding past CastHelpers-owned managed frames after unwinding out of the native write barrier.
  • Identifies CastHelpers frames via the owning MethodTable to remain stable across tiered compilation.

Comment thread src/coreclr/vm/excep.cpp Outdated
Comment thread src/coreclr/vm/excep.cpp Outdated
Comment thread src/coreclr/vm/excep.cpp Outdated
@jkotas
Copy link
Copy Markdown
Member

jkotas commented Apr 21, 2026

@EgorBo FYI

TriggerDataBreakpoint plants a deferred native patch when a data breakpoint fires
inside a write barrier. The patch was created with GetFP() (the base pointer register),
but MatchPatch computes frame pointers via GetRegdisplayStackMark which uses SP on
AMD64 and PCTAddr on x86. This mismatch caused MatchPatch to reject the patch, so
the deferred data breakpoint never fired.

Fix by using LEAF_MOST_FRAME to bypass the frame pointer check in MatchPatch. This is
safe because the patch is thread-bound (MatchPatch validates the thread) and is a
one-shot patch, so the recursive false-match scenario the frame check guards against
does not apply.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tommcdon
Copy link
Copy Markdown
Member Author

/ba-g failures are unrelated

@tommcdon tommcdon merged commit 2aba648 into dotnet:main Apr 23, 2026
90 of 109 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants