Skip to content

import gdb

Occasionally I see questions about how to import gdb from the ordinary Python interpreter.  This turns out to be surprisingly easy to implement.

First, a detour into PIE and symbol visibility.

“PIE” stands for “Position Independent Executable”.  It uses essentially the same approach as a shared library, except it can be applied to the executable.  You can easily build a PIE by compiling the objects with the -fPIE flag, and then linking the resulting executable with -pie.  Normally PIEs are used as a security feature, but in our case we’re going to compile gdb this way so we can have Python dlopen it, following the usual Python approach: we install it as and add a a module initialization function, init_gdb. (We actually name the module “_gdb“, because that is what the gdb C code creates; the “gdb” module itself is already plain Python that happens to “import _gdb“.)

Why install the PIE rather than make a true shared library?  It is just more convenient — it doesn’t require a lot of configure and Makefile hacking, and it doesn’t slow down the build by forcing us to link gdb against a new library.

Next, what about all those functions in gdb?  There are thousands of them… won’t they possibly cause conflicts at dlopen time?  Why yes… but that’s why we have symbol visibility.  Symbol visibility is an ELF feature that lets us hide all of gdb’s symbols from any dlopen caller.  In fact, I found out during this process that you can even hide main, as seems to ignore visibility bits for this function.

Making this work is as simple as adding -fvisibility=hidden to our CFLAGS, and then marking our Python module initialization function with __attribute__((visibility("default"))).  Two notes here.  First, it’s odd that “default” means “public”; just one of those mysterious details.  Second, Python’s PyMODINIT_FUNC macro ought to do this already, but it doesn’t; there’s a Python bug.

Those are the low-level mechanics.  At this point gdb is a library, albeit an unusual one that has a single entry point.  After this I needed a few tweaks to gdb’s startup process in order to make it work smoothly.  This too was no big deal.  Now I can write scripts from Python to do gdb things:

import gdb
gdb.execute('file ./install/bin/gdb')
print 'sizeof = %d' % gdb.lookup_type('struct minimal_symbol').sizeof


$ python

Soon I’ll polish all the patches and submit this upstream.


  1. Daniel Jacobowitz wrote:

    Re: main, I don’t think LD is doing anything special; it can have restricted visibility after linking because it’s only referenced from the crt files.

    I’m surprised the tweaks to the startup process were easy, but, nice job :-)

    Thursday, January 2, 2014 at 2:33 pm | Permalink
  2. tom wrote:

    Thanks, Daniel. I hadn’t thought about the crt files, but that makes perfect sense to me.

    Tuesday, January 7, 2014 at 3:11 am | Permalink
  3. Paul wrote:

    Been looking out for something like this for a while.

    I have a script that does a post-mortem analysis of core files at work. That involves two scripts – one to parse command lines, do some general housekeeping, then fire up gdb. Then the “real” code kicks with a python script to do all the hard work.

    Having it all in one script will be so much cleaner.

    Also, getting “import gdb” to operate properly in Eclipse would be a bonus.

    Monday, March 24, 2014 at 8:56 pm | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *