Skip to content

Conversation

@matouskozak
Copy link
Member

This PR implements support for setting and handling user breakpoints (System.Diagnostics.Debugger.Break()) in interpreted code.

Key Changes

Execution Control Abstraction (executioncontrol.h/cpp)

  • Introduced IExecutionControl interface to abstract breakpoint operations across different execution strategies. Currently just for interpreter but will be extended to other codegens.
  • Implemented InterpreterExecutionControl class for interpreter-specific bytecode patching
  • ApplyPatch(): Replaces bytecode instruction with INTOP_BREAKPOINT opcode
  • UnapplyPatch(): Restores original bytecode instruction

Patch Mechanism:

  • Interpreter breakpoints work by patching bytecode directly with INTOP_BREAKPOINT instruction
  • Original opcode is saved in the patch structure for restoration

Exception Flow:

  1. Interpreter hits INTOP_BREAKPOINT opcode
  2. Raises STATUS_BREAKPOINT exception with bytecode context
  3. Exception filter routes to FirstChanceNativeException()
  4. Debugger controller dispatches to appropriate breakpoint handler
  5. Original opcode is restored during patch skip activation

Address Handling:

  • Interpreter breakpoints use bytecode addresses, not native addresses
  • Special handling in patch matching to avoid comparing bytecode address with native IP
  • Exception information provides both bytecode address and frame context
image

TODOs

  • JIT completion notification handling needs revisiting for interpreter code. I've disabled it as it wasn't needed for user breakpoints.
  • IP adjustment logic uses hardcoded 3-byte offset. Not sure what is the reason for that...
  • When I tried calling FirstChanceNativeException() directly from InterpBreakpoint, I hit issues with thread and stack limit asserts, thus I went back to raising and filtering the exception.

@matouskozak matouskozak added NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) area-System.Diagnostics-coreclr labels Nov 24, 2025
#ifdef FEATURE_INTERPRETER
EECodeInfo codeInfo((PCODE)patch->address);
IJitManager* pJitManager = codeInfo.GetJitManager();
if (pJitManager != NULL && pJitManager == ExecutionManager::GetInterpreterJitManager())
Copy link
Member

Choose a reason for hiding this comment

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

Once the JIT abstraction is implemented, can we remove this condition?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, if we implement the HardwareExecutionControl, we should be able to just call pJitManager->GetExecutionControl()->ApplyPatch(patch); without any checks.

@matouskozak matouskozak force-pushed the prototype-interp-user-breakpoints branch from 0d9c6bc to 5b087e1 Compare November 25, 2025 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Diagnostics-coreclr NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants