Repository navigation
Add experimental debugger support for JIT-compiled C++ - #167
conrade-ctc wants to merge 1 commit into
Conversation
|
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 |
Vipul-Cariappa
left a comment
There was a problem hiding this comment.
I have only looked through some of the READMEs. I wanted to know why GDB? I believe LLDB provides better API support than GDB. With GDB, you are working with pipes and parsing the output as though you are running it in a shell.
| @@ -0,0 +1,26 @@ | |||
| """gdb extension for processes that run cppjit. | |||
There was a problem hiding this comment.
Can we have type hints for all the Python files in python/cppjit-debugger folder?
Will make it a bit easier to maintain and review the code.
There was a problem hiding this comment.
Done: all the files in python/cppjit-debugger have type hints now, and mypy finds no issues. The files use from __future__ import annotations, because gdb can embed an older Python.
c0b4377 to
4031ac2
Compare
|
Thanks for the review! The extension does not use pipes. gdb embeds Python, so the API calls run in the gdb process: a frame filter shows the Python frames, and the commands and pretty printers read the memory of the inferior. One place parses text, the output of I chose gdb because it is the default debugger on Linux, and it has the JIT interface and DAP built in. I agree that LLDB has a good API. The CPython decoder ( |
4e894a9 to
c20e18f
Compare
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 -fstandalone-debug. 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++. The example has notes for agents that continue the work (AGENTS.md). Co-developed-with-the-help-of: Claude Code (Opus 5.5, human in the loop)
c20e18f to
19c9543
Compare
|
It is also worth looking at how https://github.com/vgvassilev/clad recently implemented the no-source debug support (especially for lldb). That might be helpful here, too. |
My plan is to do a second pass after this lands that adds separate support for lldb, and I'll take a look at how it's done in clad. I was actually hoping to ask another person to do this that is in interested in this project, and I would oversea how they do it to make sure it is sensible ;) That way, I'm getting someone else interested in the project, and can parallelize :) Okay with you to do that as a separate PR after this lands? |
Yes, absolutely! |
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=ONhas it. Without the option, the build has no new code, exported symbols or package files, andpython/cppjitdoes not change.In a build with the support,
CPPJIT_DEBUGGER_SUPPORT=1starts a debug session:-g -O0 -fstandalone-debug. With Write interpreter inputs to files for debuggers (experimental) CppInterOp#1156, each C++ input goes to a file, so gdb shows the source and bindsfile:linebreakpoints, also in headers thatcppjit.includeloads.cppjit.debuggeradds Python line breakpoints and steps throughsys.monitoring.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-gdbuses it from VS Code through gdb's DAP server (gdb 16 or later). A small DAP proxy adds Python breakpoints, and steps between Python and C++. The demo reads a JSON file with nlohmann/json, and loads a prebuilt library without its source. ItsAGENTS.mdhas notes for whoever continues the work, for example on lldb support.Notes for review:
CPPJIT_WITH_DEBUGGER_SUPPORT: a hook pair around each JIT call inWrapperCall, a few exported variables for the debugger, and the import ofcppjit.debuggerin the module init.CPPInstancefields. I think that is acceptable for an experimental feature, but a change of these layouts needs an update here.debuggerCI job builds with the option and runstest/test_debugging.pywith gdb. It fails if a test skips. The other cells skip the gdb tests, but run the two decoder tests from the source tree. Locally (Linux, gdb 16.3, CPython 3.13), all 26 tests pass with the option, and so does the full suite.test_debugging.pyhas no Bazel target.file:linebreakpoints 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)