[clr-interp] Support for breakpoints and stepping#123251
Merged
matouskozak merged 32 commits intodotnet:mainfrom Mar 2, 2026
Merged
[clr-interp] Support for breakpoints and stepping#123251matouskozak merged 32 commits intodotnet:mainfrom
matouskozak merged 32 commits intodotnet:mainfrom
Conversation
11 tasks
ed5ce4c to
dce1adc
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This work-in-progress pull request adds support for managed debugger breakpoints in the CoreCLR interpreter. The changes extend the existing user breakpoint support (e.g., Debugger.Break()) to support IDE breakpoints and enable setting breakpoints when the program is stopped.
Changes:
- Adds interpreter single-step thread state flag and supporting methods
- Introduces new
INTOP_SINGLESTEPopcode for step-over operations - Implements
InterpreterWalkerto analyze interpreter bytecode for debugger stepping - Modifies breakpoint execution logic to distinguish between IDE breakpoints and step-out breakpoints
- Enables JIT completion notifications for interpreter code
- Pre-inserts IL offset 0 entry in the IL-to-native map to support method entry breakpoints
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/vm/threads.h | Adds TSNC_InterpreterSingleStep thread state flag and related methods |
| src/coreclr/vm/jitinterface.cpp | Removes interpreter code exclusion from JITComplete notifications |
| src/coreclr/vm/interpexec.cpp | Implements breakpoint and single-step handling with opcode replacement |
| src/coreclr/vm/codeman.h | Adds IsInterpretedCode() helper method |
| src/coreclr/interpreter/intops.h | Adds helper functions to classify interpreter opcodes |
| src/coreclr/interpreter/inc/intops.def | Defines INTOP_SINGLESTEP opcode |
| src/coreclr/interpreter/compiler.cpp | Pre-inserts IL offset 0 mapping for method entry breakpoints |
| src/coreclr/debug/ee/interpreterwalker.h | Declares InterpreterWalker class for bytecode analysis |
| src/coreclr/debug/ee/interpreterwalker.cpp | Implements bytecode walker for debugger stepping operations |
| src/coreclr/debug/ee/functioninfo.cpp | Uses GetInterpreterCodeFromInterpreterPrecodeIfPresent for code address |
| src/coreclr/debug/ee/executioncontrol.h | Defines BreakpointInfo structure and GetBreakpointInfo method |
| src/coreclr/debug/ee/executioncontrol.cpp | Implements INTOP_SINGLESTEP patch support and breakpoint info retrieval |
| src/coreclr/debug/ee/controller.h | Includes interpreterwalker.h header |
| src/coreclr/debug/ee/controller.cpp | Implements TrapStep for interpreter using InterpreterWalker |
| src/coreclr/debug/ee/CMakeLists.txt | Adds interpreterwalker source files to build |
This was referenced Jan 30, 2026
Open
noahfalk
reviewed
Jan 31, 2026
noahfalk
reviewed
Jan 31, 2026
noahfalk
reviewed
Feb 3, 2026
- New InterpreterWalker class decodes bytecode control flow for stepping - Update TrapStep to use InterpreterWalker for interpreted code - Add per-thread TSNC_InterpreterSingleStep flag for step tracking - ApplyPatch now uses INTOP_SINGLESTEP vs INTOP_BREAKPOINT based on flag - Handle INTOP_SINGLESTEP in interpreter execution loop
- needed for step-in support in virtual calls
53c3009 to
bbc1c9f
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/coreclr/debug/ee/controller.h:569
- DebuggerControllerPatch::IsActivated relies on m_interpActivated for interpreter patches to avoid treating opcode==0 as “not active”. However, there are activation paths where a patch can become logically active without going through InterpreterExecutionControl::ApplyPatch (e.g., when another patch already exists at the same address and activation is skipped by copying the opcode). In those cases, if the original opcode is 0 (INTOP_RET), IsActivated will still return false, breaking the invariants that bound patches are activated. Ensure m_interpActivated is set/cleared consistently for all interpreter patch activation/deactivation paths, not just ApplyPatch/UnapplyPatch.
bool IsActivated()
{
#ifdef FEATURE_INTERPRETER
// m_interpActivated is set only by InterpreterExecutionControl::ApplyPatch
if (m_interpActivated)
{
_ASSERTE(address != NULL);
return TRUE;
}
#endif // FEATURE_INTERPRETER
// Patch is activate if we've stored a non-zero opcode
// Note: this might be a problem as opcode 0 may be a valid opcode (see issue 366221).
if( PRDIsEmpty(opcode) ) {
return FALSE;
}
// Patch is active, so it must also be bound
_ASSERTE( address != NULL );
return TRUE;
}
BrzVlad
approved these changes
Feb 25, 2026
noahfalk
approved these changes
Feb 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds debugger support for the CoreCLR interpreter, enabling IDE breakpoints and single-stepping functionality.
Key Changes
Breakpoint Support:
INTOP_BREAKPOINTopcode injectionApplyPatch/UnapplyPatchfor interpreter code patchesINTOP_RET)Single-Stepping Support:
InterpreterStepHelperclass to encapsulate step setup logicTrapInterpreterCodeStepfor step-in/step-over/step-outOnMethodEnterfromINTOP_DEBUG_METHOD_ENTERto notify debugger of method entry (needed for indirect calls)Interpreter Compiler Changes:
INTOP_DEBUG_SEQ_POINTfor placing breakpoints at{as NOPs get collapsed.Testing
Notes/TODOs
PRDIsEmpty(opcode)activation check with explicitm_activatedflag #124499HardwareExecutionControlderived class, createInterpreterExecutionControlfor interpreter support