Tuesday, January 31, 2012

Exploring the Gdb Python API with IPython

Exploring the Gdb Python API with IPython

I've found a way to explore GDB's nice Python API in a comfortable programming environment with Python name completion by using IPython.

Save the following content in $HOME/bin/gdbipy:

#!/usr/bin/gdb --python
# vim: set filetype=python:

from IPython.zmq.ipkernel import IPKernelApp

app = IPKernelApp.instance()

Running gdbipy would start an ipython "kernel" within the gdb process:

$ chmod +x ~/bin/gdbipy
$ gdbipy 
[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing kernel-23135.json

In another terminal, run:

$ ipython console --existing kernel-23135.json

In [1]: import gdb

In [2]: gdb.<TAB>
Display all 166 possibilities? (y or n)
gdb.ARCH_FRAME                   gdb.SYMBOL_LOC_REGPARM_ADDR

You can quit the ipython console and restart it at anytime without losing state.

Here's an example session:

$ ipython console --existing kernel-23735.json

In [2]: gdb.execute('file /bin/cat')

In [3]: gdb.execute('start')

In [4]: o = gdb.execute('disassemble exit', to_string=True); print o
Dump of assembler code for function __GI_exit:
   0x0000003c902399a0 <+0>: lea    0x375cc1(%rip),%rsi        # 0x3c905af668 <__exit_funcs>
   0x0000003c902399a7 <+7>: sub    $0x8,%rsp
   0x0000003c902399ab <+11>: mov    $0x1,%edx
   0x0000003c902399b0 <+16>: callq  0x3c902398a0 <__run_exit_handlers>
End of assembler dump.

In [5]: print gdb.parse_and_eval('main').type
int (int, char **)

Having an interactive Python environment with name completion makes exploring and learning the gdb.Value API quite a bit easier.

The reason we need to run "ipython console" in a separate process from GDB is so that the two don't fight over the terminal settings. You can experience what that's like by changing the content of the gdbipy script to just "import IPython; IPython.embed()" which embeds an IPython read-eval-print loop in-process. The result is partially garbled terminal output and non functional TAB completion. The two process IPython console solution presented requires IPython 0.12+ and works out of the box on Fedora 16.

See Also

Update Feb 2: changed IPython version requirement from 0.11 to 0.12. After Paul Ivanov pointed it out in the comments.


  1. minor correction: your examples require IPython 0.12 - the .json connection files did not happen until after 0.11 was released, and the same for the two-process terminal based 'console'.

    1. @Paul Ivanov, thanks for the corrections. Before writing down the IPython version requirement, I took a quick look in git to make sure the zmq.IPKernelApp snippet would work in 0.11 but missed the fact that I'm using other features introduced in 0.12.

  2. Thanks for this article Scott.

    I've just stumbled on this API, and I can't believe I didn't know about it before. I wish the documentation out there was a bit better.

    I'm throwing together a repo for example scripts and such. I've been focused on stack exploration and data plotting (using matplotlib).

    If anyone has good scripts worth throwing in there, or a better way to do things. I'd be glad to hear about it.



  3. Scott, I couldnt get my gdb to respond to the
    #!/usr/bin/gdb --python
    line. Im using v gdb 7.4 and it doesnt understand --python?

    1. @johnwoodinfinityphase, "gdb --python" should show: "gdb: Python script file name required". If it doesn't, your gdb is compiled without Python support.

      One easy way to fix this is to clone http://sourceware.org/git/?p=gdb.git and checkout the gdb_7_5-branch and build from source while passing "--with-python" to configure. (You can see how Fedora builds its gdb here: http://pkgs.fedoraproject.org/cgit/gdb.git/tree/gdb.spec
      Search for "./configure")

      This way, you get to try the new GDB 7.5 features like "dprintf" as well (http://sourceware.org/git/?p=gdb.git;a=blob;f=gdb/NEWS;h=dba6937459e8b8e6d617acf420ca281abd450b44;hb=HEAD)

      Where did you get your existing gdb from?