August 6th, 2024

Debugging running Python scripts with PDB via GDB

The blog post explains using GDB to debug running Python scripts, emphasizing the need for caution in production environments and suggesting further development for a more reliable debugging solution.

Read original articleLink Icon
Debugging running Python scripts with PDB via GDB

The blog post discusses a method for debugging running Python scripts using GDB (GNU Project Debugger) in conjunction with PDB (Python Debugger). It highlights that CPython, the reference implementation of Python, is written in C and can be debugged like any native program. The author provides an example of a Python script that can be debugged while it is running. By attaching GDB to the Python interpreter process, users can access detailed debugging information, especially when debug symbols are enabled. The author explains how to set a breakpoint on the PyEval_SaveThread function and execute arbitrary Python code in the current execution frame using PyRun_SimpleString. While this method has been successful in testing, the author cautions against using it in production environments due to potential risks of corrupting the CPython state or crashing the script. Additionally, if the script runs without a terminal, it may require redirecting stdin and stdout for interaction. The author expresses interest in further developing a more reliable solution for this debugging technique.

- GDB can be used to debug running Python scripts by attaching to the interpreter process.

- Debugging symbols enhance the information available during debugging sessions.

- Breakpoints can be set in GDB to execute Python code in the current execution frame.

- Caution is advised against using this method in production due to potential risks.

- Further development of a more reliable debugging solution is suggested.

Link Icon 5 comments
By @senkora - 9 months
I like to add this function to my Python scripts so that I can drop into pdb by sending a signal:

    import signal

    def sigusr1_handler(signum, stack):
        breakpoint()

    signal.signal(signal.SIGUSR1, sigusr1_handler)
And then I can drop into pdb by sending a signal:

    $ kill -s sigusr1 $PID
I also want to highlight something non-obvious about debugging mixed native and Python code. Because Python is interpreted, it is possible to run both gdb and pdb on a process at the same time, and set breakpoints using both, without issue. This can be really nice when you're working on Python bindings.
By @swyx - 9 months
i was one of the lucky 10,000 that discovered pdb a year ago. jsut wanted to point out that you can alias your normal `python` command to run `python -m pdb -c c` and it will always run in pdb mode for most development https://twitter.com/jeremyphoward/status/1756541454288396402
By @lathiat - 9 months
You can also inspect python frames, objects/variables etc directly from GDB: https://docs.python.org/3/howto/gdb_helpers.html
By @eddyg - 9 months
Probably worth mention madbg⁽¹⁾, a fully-featured remote and preemptive debugger for Python with both a CLI and an API, that allows attaching to running programs preemptively (but does not require gdb).

⁽¹⁾https://github.com/kmaork/madbg