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()
app.initialize([])
app.start()

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
gdb.BP_ACCESS_WATCHPOINT         gdb.SYMBOL_LOC_STATIC
gdb.BP_BREAKPOINT                gdb.SYMBOL_LOC_TYPEDEF
...

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.