Debugging Dynamically Loaded C Extensions with gdb

Credit: Joseph VanAndel, Michael Aivazis

Problem

A dynamically loaded C/C++ Python extension is giving you trouble on Unix or a Unix-like platform, and you would like to use the interactive debugger gdb to find out more about what’s wrong.

Solution

One way to find the cause of core dumps or other serious trouble with a C Python extension is to compile the extension source with -g and then follow these steps (you may also want to recompile any other extensions you use, such as Numeric, with -g):

% gdb /usr/bin/python2.1
(gdb) br _PyImport_LoadDynamicModule
(gdb) cont   # Repeat until your extension is loaded
(gdb) finish # to load your extension
(gdb) br wrap_myfunction  # the entry point in your code
(gdb) disable 1   # don't want to break for more modules being loaded
(gdb) continue

Discussion

If a dynamically loaded C/C++ extension is causing Python to core dump, or causing some other kind of serious trouble, this recipe can help you find out the root cause by showing a technique to debug your extension using gdb (if you use Unix or a Unix-like platform, and gdb is your debugger of choice). Note that the overall concept generalizes to other debuggers with abilities similar to gdb’s. You cannot set a break on your function all at once, because your function lives in a dynamic library (shared object) that isn’t initially loaded. However, you can break in the PyImport_LoadDynamicModule function and eventually (when your module is at long last loaded) get control at the debugger prompt after your module is in memory. You will be able, at last, to set the breakpoint you need.

This technique works. However, if you often do this kind of thing, the process of stepping through all the modules, as Python loads them at startup, can easily become tedious. There’s a handier alternative, although it’s more invasive, because it requires you to modify your Python sources and rebuild Python from them.

The key idea of this handier alternative is to add a do-nothing function somewhere in the body of code that Python loads immediately. Specifically, you can edit the Modules/main.c file to include one new function:

void Py_DebugTrap(void) { }

In whatever extension you’re debugging, add a call to Py_DebugTrap right where you want to break into the code. The Py_DebugTrap symbol is immediately available when you start gdb, because the symbol lives in main.c. So you can immediately set a breakpoint there when you are at the gdb prompt, then continue. This even works in parallel under MPI.

See Also

The gdb online documentation (just type help at the interactive prompt), manpages, and online manual (http://www.gnu.org/manual/gdb-4.17/gdb.html).

Get Python Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.