Skip to content

[clr-interp] Support for breakpoints and stepping#123251

Merged
matouskozak merged 32 commits intodotnet:mainfrom
matouskozak:interpreter-breakpoints
Mar 2, 2026
Merged

[clr-interp] Support for breakpoints and stepping#123251
matouskozak merged 32 commits intodotnet:mainfrom
matouskozak:interpreter-breakpoints

Conversation

@matouskozak
Copy link
Member

@matouskozak matouskozak commented Jan 16, 2026

Summary

This PR adds debugger support for the CoreCLR interpreter, enabling IDE breakpoints and single-stepping functionality.

Key Changes

Breakpoint Support:

  • Enable breakpoints in interpreter via INTOP_BREAKPOINT opcode injection
  • Add IL offset 0 → IR offset 0 mapping for method entry breakpoints
  • Refactor ApplyPatch/UnapplyPatch for interpreter code patches
  • Add activation flag for interpreter patches (needed because opcode 0 is valid INTOP_RET)

Single-Stepping Support:

  • Add InterpreterStepHelper class to encapsulate step setup logic
  • Per-thread context bypass address/opcode fields for resuming past breakpoints
  • Implement TrapInterpreterCodeStep for step-in/step-over/step-out
  • Call OnMethodEnter from INTOP_DEBUG_METHOD_ENTER to notify debugger of method entry (needed for indirect calls)

Interpreter Compiler Changes:

  • Add INTOP_DEBUG_SEQ_POINT for placing breakpoints at { as NOPs get collapsed.

Testing

  • Verified IDE breakpoints work with interpreted code
  • Single-stepping (step-in, step-over, step-out) functional
  • No regressions to existing debugger support verified locally using diagnostictests

Notes/TODOs

  • Stack walking workaround needs to be reverted once proper fix is in place
  • m_interpActivated should be generalized to all patches (stop using opcode == 0 as "not active") [debugger] Replace PRDIsEmpty(opcode) activation check with explicit m_activated flag #124499
  • s_interpOpLen / opcode name tables in executioncontrol.cpp are debug logging aids — TODO remove
  • Long-term plan: Extract JIT-specific code into HardwareExecutionControl derived class, create InterpreterExecutionControl for interpreter support

@matouskozak matouskozak self-assigned this Jan 16, 2026
@matouskozak matouskozak added NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) area-Diagnostics-coreclr labels Jan 16, 2026
@matouskozak matouskozak force-pushed the interpreter-breakpoints branch from ed5ce4c to dce1adc Compare January 16, 2026 08:52
Copilot AI review requested due to automatic review settings January 30, 2026 10:59
Copy link
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

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_SINGLESTEP opcode for step-over operations
  • Implements InterpreterWalker to 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

Copilot AI review requested due to automatic review settings January 30, 2026 11:19
Copy link
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

Copilot reviewed 19 out of 19 changed files in this pull request and generated 9 comments.

Copy link
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

Copilot reviewed 21 out of 21 changed files in this pull request and generated 8 comments.

- 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
Copilot AI review requested due to automatic review settings February 24, 2026 11:56
@matouskozak matouskozak force-pushed the interpreter-breakpoints branch from 53c3009 to bbc1c9f Compare February 24, 2026 11:56
Copy link
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

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;
    }

Copilot AI review requested due to automatic review settings February 27, 2026 08:42
Copy link
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

Copilot reviewed 21 out of 21 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings March 1, 2026 21:20
Copy link
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

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

@matouskozak matouskozak merged commit a550606 into dotnet:main Mar 2, 2026
108 of 113 checks passed
@matouskozak matouskozak deleted the interpreter-breakpoints branch March 2, 2026 13:29
@matouskozak matouskozak restored the interpreter-breakpoints branch March 4, 2026 18:06
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.

6 participants