Multi-frame navigation in a Python debugger

, Wellesley, MA

I learned to program in C, and I got used to GDB’s multi-frame navigation. When GDB prints the stack, it numbers the frames. frame [n] tells GDB to go directly to frame n. Its up [n] and down [n] commands move up and down the stack by `n’ frames.

...
Breakpoint 1, zero () at framenav.c:4
(gdb) where
#0  zero () at framenav.c:4
#1  0x0000000100000de8 in one () at framenav.c:9
#2  0x0000000100000e08 in two () at framenav.c:14
#3  0x0000000100000e28 in three () at framenav.c:19
#4  0x0000000100000e44 in main (argc=1, argv=0x7fff5fbff750) at framenav.c:23
(gdb) frame 3
#3  0x0000000100000e28 in three () at framenav.c:19
(gdb) frame 1
#1  0x0000000100000de8 in one () at framenav.c:9
(gdb) up 3
#4  0x0000000100000e44 in main (argc=1, argv=0x7fff5fbff750) at framenav.c:23
(gdb) down 4
#0  zero () at framenav.c:4

For as long as I’ve used Python’s debugger pdb, I’ve wondered why its up and down commands can only move one frame at a time. Navigating a deep stack using pdb is pretty tedious. You can use aliases to move more than one frame at a time, but even then, you have the burden of counting frames.

Here’s an alternative, implemented as a patch for pdb++, a drop-in pdb replacement.

With the patch, pdb++’s w numbers frames, frame [n] moves directly to frame n, up [n] moves up n frames, and down [n] moves down n frames.

(Pdb++) w
[0]
  /usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py(387)run()
-> exec cmd in globals, locals
[1]
  <string>(1)<module>()
[2]
  /Users/mlm/tmp/framenav.py(11)<module>()
-> two()
[3]
  /Users/mlm/tmp/framenav.py(8)two()
-> three()
[4]
  /Users/mlm/tmp/framenav.py(5)three()
-> four()
[5]
> /Users/mlm/tmp/framenav.py(2)four()
-> pass
(Pdb++) frame 4
[4]
> /Users/mlm/tmp/framenav.py(5)three()
-> four()
(Pdb++) up 3
[1]
> <string>(1)<module>()
(Pdb++) down 4
[5]
> /Users/mlm/tmp/framenav.py(2)four()
-> pass

Although pdb and pdb++ number Python stack frames the opposite order that GDB numbers C stack frames, up and down move in the same logical order — opposite numerical order — as their respective GDB commands. up moves toward the outermost frame, and down moves toward the innermost frame.

Enjoyed reading this post? Discuss it on Reddit, or follow me on Twitter.