Skip to content

Add experimental debugger support for JIT-compiled C++ - #167

Open
conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
chicagotrading:upstreaming/jit-debugging
Open

conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
chicagotrading:upstreaming/jit-debugging

Conversation

@conrade-ctc

Copy link
Copy Markdown
Contributor

This adds experimental support to debug JIT-compiled C++ at the source level with gdb, from Python and from VS Code. It is off by default: only a build with -DCPPJIT_ENABLE_DEBUGGER_SUPPORT=ON has it. Without the option, the build has no new code, exported symbols or package files, and python/cppjit does not change.

In a build with the support, CPPJIT_DEBUGGER_SUPPORT=1 starts a debug session:

  • The JIT compiles with -g -O0. With Write interpreter inputs to files for debuggers (experimental) CppInterOp#1156, each C++ input goes to a file, so gdb shows the source and binds file:line breakpoints, also in headers that cppjit.include loads.
  • cppjit.debugger adds Python line breakpoints and steps through sys.monitoring.
  • A gdb extension (cppjit/debugger/gdb) shows the Python frames between the C++ frames, with the variables of both. It reads CPython's _Py_DebugOffsets, so CPython needs no debug information (3.13 or later).
  • examples/vscode-gdb uses it from VS Code through gdb's DAP server (gdb 14 or later). A small DAP proxy adds Python breakpoints, and steps between Python and C++.

Notes for review:

  • The C++ changes are behind CPPJIT_WITH_DEBUGGER_SUPPORT: a hook pair around each JIT call in WrapperCall, a few exported variables for the debugger, and the import of cppjit.debugger in the module init.
  • The gdb extension also reads a few layouts that the debug offsets do not give: frame globals, dict entries, and the CPPInstance fields. I think that is acceptable for an experimental feature, but a change of these layouts needs an update here.
  • CI does not build with the option, so the gdb tests in test/test_debugging.py skip there. The two decoder tests run in CI from the source tree. Locally (Linux, gdb 16.3, CPython 3.13), all 21 tests pass with the option. I can add a CI cell with the option if you want one.
  • file:line breakpoints need the CppInterOp change and a pin that has it. Breakpoints by function name work without it.

🤖 Done with the help of Claude Code (Opus 5.5, human in the loop)

The support is off by default. Build with
-DCPPJIT_ENABLE_DEBUGGER_SUPPORT=ON to get it. Without the option, the
build has no new code, symbols or files.

In a build with the support, CPPJIT_DEBUGGER_SUPPORT=1 starts a debug
session:

- The JIT compiles with -g -O0. CppInterOp writes each C++ input to a
  file in CPPINTEROP_JIT_SOURCE_DIR, so gdb shows the source and binds
  FILE:LINE breakpoints.
- cppjit.debugger copies in-memory Python source to files, and adds
  Python line breakpoints and steps through sys.monitoring.
- A gdb extension shows the Python frames between the C++ frames, with
  the variables of both. It reads CPython's _Py_DebugOffsets, so CPython
  needs no debug information.
- examples/vscode-gdb uses it from VS Code through gdb's DAP server. A
  DAP proxy adds Python breakpoints and steps between Python and C++.

Co-developed-with-the-help-of: Claude Code (Opus 5.5, human in the loop)
@aaronj0

aaronj0 commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

Nice! So that your changes are tested on the CI, can you add a commit like cc7edf7 pointing to your CppInterOp remote and branch? That would stack your changes and any iterations on compiler-research/CppInterOp#1156 will automatically reflect here

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants