gdb 7 onwards is scriptable using an embedded CPython 2.*, giving the ability to write fragments of Python to add new
commands, and to tell gdb how to pretty-print data, etc. (A couple of years ago I wrote such code to make it easier to
debug CPython; see http://fedoraproject.org/wiki/Features/EasierPythonDebugging )
I'm attaching a script I've written to help debug PyPy. It's a work in progress so far, but it's able to print RPython
strings, and some PyPy frame information.
For example, if I run
$ gdb --eval-command="break pypy_g_PyFrame_run" --eval-command="run" --args pypy
I get this output when the breakpoint is hit:
Breakpoint 1, pypy_g_PyFrame_run (l_self_11960=Frame for app_main.py:run_toplevel:42) at interpreter_pyframe.c:48
Note how the frame object has been pretty-printed as "Frame for app_main.py:run_toplevel:42"
I'm attaching what a full backtrace looks like with these hooks for a pypy process waiting at the interactive prompt
(full-backtrace.txt): numerous frames are visible. Unfortunately, many values are optimized out, though.
Of course this code is specific to the C backend, and it's probably sensitive to translation options - but my feeling is
that every little helps when debugging the generated C code.
I copy the file to:
alongside the DWARF data (where I've been editing it in place).
gdb will load this on startup when debugging /usr/lib64/pypy-1.9/pypy (aka /usr/bin/pypy). My plan is to package this
file within my rpms so that it's within the debuginfo rpm (I do something similar for CPython on Fedora/RHEL).
Presumably this file should live somewhere in the pypy source tree (where?) Should I create a branch on bitbucket, and
hack on it there?
Motivation: although PyPy's generated C code may be perfect, as soon as you link 3rd-party code into the
process (e.g. via extension modules, ctypes, or some other FFI), the process runs the risk of crashes
induced by bugs in that 3rd party code. Hence it's useful to have some way of debugging the process and
figuring out e.g. what thread is doing what. (For example: pointers getting freed by 3rd party code that
shouldn't have freed them, refcounting bugs in extension modules, random pointer corruption, etc etc)